### Basic Relic App Setup Source: https://context7.com/serverpod/relic/llms.txt Demonstrates the basic setup of a Relic application, including middleware and a simple GET endpoint. ```APIDOC ## Relic App Example ### Description This example shows how to initialize a `RelicApp`, apply middleware using the `use` method, and define a GET route for `/users/:id`. ### Method GET ### Endpoint `/users/:id` ### Parameters #### Path Parameters - **id** (String) - Required - The ID of the user to retrieve. #### Request Body None ### Request Example None ### Response #### Success Response (200) - **body** (Body) - The response body, which is a `Body.fromString` containing the user ID. #### Response Example ``` User ``` ## Middleware Usage ### Description Demonstrates how to apply middleware to a Relic application using the `use` method. This example applies the `logRequests` middleware to all requests. ### Method All (applied globally) ### Endpoint `/` (root path, applies to all subsequent routes) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) - **body** (Body) - The response body from the matched route. #### Response Example None ## RelicApp Serve ### Description Starts the Relic application server, listening on localhost. ### Method `app.serve()` ### Endpoint N/A (starts a server) ### Parameters None ### Request Example None ### Response None (starts a server) ``` -------------------------------- ### Respond with 'Hello World!' on the homepage (GET /) Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/03-routing.md Example of using a convenience method to handle GET requests on the root path, returning a simple string response. ```dart app.get('/', (final Request request) async { return Response.ok(body: Body.fromString('Hello World!')); }); ``` -------------------------------- ### Install Documentation Dependencies Source: https://github.com/serverpod/relic/blob/main/doc/site/README.md Navigate to the doc/site directory and run 'make install' to install project dependencies. ```bash cd doc/site make install ``` -------------------------------- ### Run First Relic Server Source: https://github.com/serverpod/relic/blob/main/packages/relic_io/README.md A 'Hello World' example demonstrating basic Relic app setup, routing with path parameters, middleware, and a custom fallback handler. This server listens on port 8080 by default. ```dart import 'package:relic/io_adapter.dart'; import 'package:relic/relic.dart'; /// A simple 'Hello World' server demonstrating basic Relic usage. Future main() async { // Setup the app. final app = RelicApp() // Route with parameters (:name & :age). ..get('/user/:name/age/:age', helloHandler) // Middleware on all paths below '/'. ..use('/', logRequests()) // Custom fallback - optional (default is 404 Not Found). ..fallback = respondWith((_) => Response.notFound(body: Body.fromString("Sorry, that doesn't compute.\n"))); // Start the server (defaults to using port 8080). await app.serve(); } const _ageParam = PathParam(#age, int.parse); /// Handles requests to the hello endpoint with path parameters. Response helloHandler(final Request req) { final name = req.pathParameters.raw[#name]; final age = req.pathParameters.get(_ageParam); return Response.ok( body: Body.fromString('Hello, $name! To think you are $age years old.\n'), ); } ``` -------------------------------- ### Create a Basic Relic 'Hello World' Server Source: https://github.com/serverpod/relic/blob/main/README.md Sets up a simple Relic application with a GET route that accepts path parameters and logs requests. Includes a custom fallback handler for unmatched routes. Ensure Dart 3.7+ is installed. ```dart import 'package:relic/io_adapter.dart'; import 'package:relic/relic.dart'; /// A simple 'Hello World' server demonstrating basic Relic usage. Future main() async { // Setup the app. final app = RelicApp() // Route with parameters (:name & :age). ..get('/user/:name/age/:age', helloHandler) // Middleware on all paths below '/'. ..use('/', logRequests()) // Custom fallback - optional (default is 404 Not Found). ..fallback = respondWith( (_) => Response.notFound( body: Body.fromString("Sorry, that doesn't compute.\n"), ), ); // Start the server (defaults to using port 8080). await app.serve(); } const _ageParam = PathParam(#age, int.parse); /// Handles requests to the hello endpoint with path parameters. Response helloHandler(final Request req) { final name = req.pathParameters.raw[#name]; final age = req.pathParameters.get(_ageParam); return Response.ok( body: Body.fromString('Hello, $name! To think you are $age years old.\n'), ); } ``` -------------------------------- ### GET / Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/03-routing.md Respond with 'Hello World!' on the homepage using the convenience GET method. ```APIDOC ## GET / ### Description Handles GET requests to the root path. ### Method GET ### Endpoint / ### Request Example (No request body specified) ### Response #### Success Response (200) - body (string) - 'Hello World!' ``` -------------------------------- ### Install Node.js Source: https://github.com/serverpod/relic/blob/main/doc/site/README.md Install Node.js using Homebrew. Ensure Node.js is installed before proceeding with other installation steps. ```bash brew install node ``` -------------------------------- ### Bootstrap Relic Application with RelicApp Source: https://context7.com/serverpod/relic/llms.txt Example of setting up a Relic application using RelicApp, defining routes, middleware, and a fallback handler. Starts the server on port 8080 by default. ```dart import 'package:relic/io_adapter.dart'; import 'package:relic/relic.dart'; Future main() async { final app = RelicApp() ..get('/user/:name/age/:age', helloHandler) ..use('/', logRequests()) ..fallback = respondWith( (_) => Response.notFound(body: Body.fromString("Not found.\n")), ); // Starts on port 8080 by default; use port: N to change. await app.serve(); } const _ageParam = PathParam(#age, int.parse); Response helloHandler(Request req) { final name = req.pathParameters.raw[#name]; final age = req.pathParameters.get(_ageParam); return Response.ok( body: Body.fromString('Hello, $name! You are $age years old.\n'), ); } ``` -------------------------------- ### Start Local Development Server Source: https://github.com/serverpod/relic/blob/main/doc/site/README.md Run 'make start' to launch a local development server. Changes are typically reflected live without a server restart. ```bash make start ``` -------------------------------- ### Complete Example: Shelf Version Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/01-getting-started/03-shelf-migration.md A full Shelf application example demonstrating routing, middleware, and serving requests. This serves as a baseline for migration. ```dart import 'package:shelf/shelf.dart'; import 'package:shelf_router/shelf_router.dart'; import 'package:shelf/shelf_io.dart' as shelf_io; void main() async { final router = Router() ..get('/users/', (Request request, String id) { final name = request.url.queryParameters['name'] ?? 'Unknown'; return Response.ok('User $id: $name'); }); final handler = Pipeline() .addMiddleware(logRequests()) .addHandler(router); await shelf_io.serve(handler, 'localhost', 8080); } ``` -------------------------------- ### Relic Basic Web Server Example Source: https://github.com/serverpod/relic/blob/main/packages/relic/skills/relic-shelf-migration/SKILL.md A complete example of a Relic application, demonstrating routing and serving HTTP requests. It mirrors the Shelf example with similar functionality. ```dart import 'package:relic/relic.dart'; Future main() async { final app = RelicApp() ..use('/', logRequests()) ..get('/users/:id', (Request request) { final id = request.rawPathParameters[#id]; final name = request.url.queryParameters['name'] ?? 'Unknown'; return Response.ok(body: Body.fromString('User $id: $name')); }); await app.serve(address: InternetAddress.loopbackIPv4, port: 8080); } ``` -------------------------------- ### Install markdownlint-cli Source: https://github.com/serverpod/relic/blob/main/doc/site/README.md Install the markdownlint-cli globally using npm. This tool helps enforce consistent markdown formatting. ```bash $ npm install -g markdownlint-cli ``` -------------------------------- ### Complete Relic Server Example with WebSockets and SSE Source: https://github.com/serverpod/relic/blob/main/packages/relic/skills/relic-websockets/SKILL.md A full example demonstrating how to set up a Relic application with both WebSocket and Server-Sent Events (SSE) endpoints. It includes necessary imports and the main server logic. ```dart import 'dart:async'; import 'dart:convert'; import 'package:relic/relic.dart'; Future main() async { final app = RelicApp() ..get('/ws', (req) { return WebSocketUpgrade((ws) async { ws.sendText('Welcome to Relic WebSocket!'); await for (final event in ws.events) { switch (event) { case TextDataReceived(text: final message): ws.sendText('Echo: $message'); case CloseReceived(): break; default: break; } } }); }) ..get('/sse', (req) { return Hijack((channel) async { channel.sink.add(utf8.encode('data: Connected\n\n')); final timer = Timer.periodic( Duration(seconds: 1), (_) => channel.sink.add(utf8.encode('data: tick\n\n')), ); await channel.sink.done; timer.cancel(); }); }); await app.serve(); } ``` -------------------------------- ### Clone and Run Relic Examples Source: https://github.com/serverpod/relic/blob/main/README.md Clones the Relic repository and executes the example application. This is useful for exploring more advanced features. ```bash git clone https://github.com/serverpod/relic.git cd relic/example dart example.dart ``` -------------------------------- ### Complete Example: Relic Version Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/01-getting-started/03-shelf-migration.md A full Relic application example mirroring the Shelf version, showcasing its integrated routing and middleware. Note the difference in middleware execution for unmatched routes. ```dart final app = RelicApp() ..use('/', logRequests()) ..get('/users/', (Request request, String id) async { final name = request.url.queryParameters['name'] ?? 'Unknown'; return Response.ok(body: Body.fromString('User $id: $name')); }); void main() async { await app.serve(8080); } ``` -------------------------------- ### Install Relic Source: https://github.com/serverpod/relic/blob/main/packages/relic/skills/relic-app-setup/SKILL.md Use these commands to create a new console project and add the Relic package. ```bash dart create -t console-full my_server cd my_server dart pub add relic ``` -------------------------------- ### Verify Dart Installation Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/01-getting-started/01-installation.md Run this command to check if your Dart SDK is installed and meets the minimum version requirement. ```bash dart --version ``` -------------------------------- ### Shelf REST API Example Source: https://context7.com/serverpod/relic/llms.txt A basic Shelf application demonstrating routing and request logging. ```dart // ---- SHELF ---- import 'package:shelf/shelf.dart'; import 'package:shelf_router/shelf_router.dart'; import 'package:shelf/shelf_io.dart' as io; void main() async { final router = Router() ..get('/users/', (Request req, String id) => Response.ok('User $id')); final handler = Pipeline().addMiddleware(logRequests()).addHandler(router); await io.serve(handler, 'localhost', 8080); } ``` -------------------------------- ### Bootstrap Server: Shelf vs. Relic Source: https://github.com/serverpod/relic/blob/main/packages/relic/skills/relic-shelf-migration/SKILL.md Compares the server bootstrapping process between Shelf and Relic. Relic simplifies the setup with a single `RelicApp` instance. ```dart import 'package:shelf_router/shelf_router.dart'; import 'package:shelf/shelf.dart'; import 'package:shelf/shelf_io.dart' as io; void main() async { final app = Router(); // Add routes... await io.serve(app, 'localhost', 8080); } ``` ```dart import 'package:relic/relic.dart'; Future main() async { final app = RelicApp() ..get('/users/:id', (Request request) { final id = request.rawPathParameters[#id]; final name = request.url.queryParameters['name'] ?? 'Unknown'; return Response.ok(body: Body.fromString('User $id: $name')); }); await app.serve(address: InternetAddress.loopbackIPv4, port: 8080); } ``` -------------------------------- ### Run the Relic server locally Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/01-getting-started/02-hello-world-example.md Execute this command to start your Dart application. ```bash dart bin/hello_world.dart ``` -------------------------------- ### Synchronous Handler Example Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/01-handlers.md Example of a simple, fast synchronous handler. Use for operations that do not require waiting. ```dart Future handler(Request req) async { return Response.ok( "Hello, ${req.method} ${req.uri.path}!", ); } ``` -------------------------------- ### Install Relic Web Server Framework Source: https://context7.com/serverpod/relic/llms.txt Instructions for adding Relic to a Dart project. Requires Dart SDK version 3.7 or higher. ```bash # Create a new project dart create -t console-full hello_world cd hello_world # Add the dependency dart pub add relic # Or manually in pubspec.yaml: # dependencies: # relic: ^ dart pub get ``` -------------------------------- ### Test the Hello World server with curl Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/01-getting-started/02-hello-world-example.md Use curl to send a GET request to the /user route with specified name and age parameters. ```bash curl http://localhost:8080/user/Nova/age/37 ``` -------------------------------- ### Pipeline Usage Example Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/99-pipeline.md Demonstrates how to use the legacy Pipeline class to compose middleware and a handler. This pattern is being replaced by router.use(). ```dart final handler = Pipeline().addMiddleware(logRequests).addHandler(myHandler); ``` -------------------------------- ### Example: Search Query with Typed Parameters Source: https://context7.com/serverpod/relic/llms.txt Demonstrates making a curl request to the search endpoint with 'query' and 'page' parameters. Shows the expected JSON response. ```bash curl "http://localhost:8080/search?query=dart&page=2" # {"query":"dart","page":2,"limit":null} ``` -------------------------------- ### Asynchronous Handler Example Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/01-handlers.md Example of an asynchronous handler. Use for operations that need to wait, such as database calls or file I/O. ```dart Future handler(Request req) async { // Simulate a database call await Future.delayed(Duration(milliseconds: 50)); return Response.ok( "Data fetched after delay", ); } ``` -------------------------------- ### GET|POST /admin Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/03-routing.md Handle both GET and POST requests to the `/admin` route using `anyOf`. ```APIDOC ## GET, POST /admin ### Description Handles both GET and POST requests to the /admin path. ### Method GET, POST ### Endpoint /admin ### Request Example (No request body specified) ### Response #### Success Response (200) (No response body specified) ``` -------------------------------- ### HTML Response Source: https://github.com/serverpod/relic/blob/main/packages/relic/skills/relic-request-response/SKILL.md Example of returning an HTML response with the correct MIME type. ```APIDOC ## HTML Response ```dart app.get('/page', (req) { final html = '

Welcome

'; return Response.ok(body: Body.fromString(html, mimeType: MimeType.html)); }); ``` ``` -------------------------------- ### Relic REST API Example Source: https://context7.com/serverpod/relic/llms.txt A basic Relic application demonstrating routing and request logging, showcasing key API differences from Shelf. ```dart // ---- RELIC ---- import 'package:relic/relic.dart'; void main() async { final app = RelicApp() ..use('/', logRequests()) ..get('/users/:id', (req) { final id = req.pathParameters.raw[#id]; return Response.ok(body: Body.fromString('User $id')); }); await app.serve(); } ``` -------------------------------- ### Example Test Structure with Given-When-Then Source: https://github.com/serverpod/relic/blob/main/CONTRIBUTING.md Demonstrates the recommended Given-When-Then structure for test descriptions and the Arrange-Act-Assert pattern for test bodies. Imports package:test and assumes a feature is available for processing. ```dart // In a file like relic/test/some_feature_test.dart import 'package:test/test.dart'; // Import your feature here void main() { group('My Feature Logic', () { test( 'Given a specific input string, ' 'when the processing function is called, ' 'then the output should be correctly formatted', () { // Arrange: Set up preconditions final input = 'test_input'; final expectedOutput = 'TEST_INPUT_PROCESSED'; // Act: Perform the action final actualOutput = processMyFeature(input); // Assert: Verify the outcome expect(actualOutput, equals(expectedOutput)); }); }); } ``` -------------------------------- ### Serve a Single File with Cache Control Source: https://github.com/serverpod/relic/blob/main/packages/relic/skills/relic-static-files/SKILL.md Serve a specific file with custom cache control headers. This example sets a 1-hour cache for 'assets/logo.svg'. ```dart app.get( '/logo.svg', StaticHandler.file( File('assets/logo.svg'), cacheControl: (req, fileInfo) => CacheControlHeader(maxAge: 3600), ).asHandler, ); ``` -------------------------------- ### Convenience Method Shortcuts Source: https://context7.com/serverpod/relic/llms.txt Register routes for common HTTP methods using convenient shortcuts like `get`, `post`, `put`, and `delete`. ```APIDOC ## GET / ### Description Handles GET requests to the root path. ### Method GET ### Endpoint / ### Request Example (No request body specified) ### Response #### Success Response (200) - **body** (Body) - The response body. ### Response Example ``` Hello World! ``` ## POST / ### Description Handles POST requests to the root path. ### Method POST ### Endpoint / ### Request Example (No request body specified) ### Response #### Success Response (200) - **body** (Body) - The response body. ### Response Example ``` POST root ``` ## PUT /user ### Description Handles PUT requests to the /user path. ### Method PUT ### Endpoint /user ### Request Example (No request body specified) ### Response #### Success Response (200) - **body** (Body) - The response body. ### Response Example ``` PUT user ``` ## DELETE /user ### Description Handles DELETE requests to the /user path. ### Method DELETE ### Endpoint /user ### Request Example (No request body specified) ### Response #### Success Response (200) - **body** (Body) - The response body. ### Response Example ``` DELETE user ``` ``` -------------------------------- ### Get Dependencies Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/01-getting-started/01-installation.md After modifying your pubspec.yaml file, run this command to fetch all project dependencies, including Relic. ```bash dart pub get ``` -------------------------------- ### Example cURL Commands for API Interaction Source: https://context7.com/serverpod/relic/llms.txt Demonstrates how to interact with the Relic server using cURL for POST requests with JSON data, file uploads, and streaming responses. ```bash curl -X POST http://localhost:8080/api/data \ -H "Content-Type: application/json" \ -d '{"name":"test"}' # {"result":"success","received":{"name":"test"}} ``` ```bash curl -X POST http://localhost:8080/upload --data-binary @bigfile.bin # Upload successful ``` ```bash curl http://localhost:8080/stream # {"item": 0} # {"item": 1} # ... ``` -------------------------------- ### Handle both GET and POST requests to '/admin' Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/03-routing.md Utilizes the `.anyOf()` convenience method to register a single handler for multiple HTTP methods (GET and POST) on the same path. This reduces code duplication when multiple methods share the same logic. ```dart app.anyOf({Method.get, Method.post}, '/admin', (final Request request) async { return Response.ok(body: Body.fromString('GET or POST request to /admin')); }); ``` -------------------------------- ### Example: Create User with JSON Body Source: https://context7.com/serverpod/relic/llms.txt Illustrates creating a user by sending a JSON payload via curl to the /api/users endpoint. Shows the expected response with the new user's ID and name. ```bash curl -X POST http://localhost:8080/api/users \ -H "Content-Type: application/json" \ -d '{"name":"Alice","email":"alice@example.com"}' # {"id":1712345678901,"name":"Alice"} ``` -------------------------------- ### Applying Middleware with router.use() Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/07-middleware.md Demonstrates how to apply middleware to specific path patterns using the `use()` method on a `RelicApp` instance. This example shows applying logging to all routes and authentication to API routes. ```dart import 'package:relic/relic.dart'; final router = RelicApp() // Apply logging to all routes ..use('/', logRequests()) // Apply authentication to API routes ..use('/api', authMiddleware()) // Define your routes ..get('/api/users', usersHandler) ..post('/api/users', createUserHandler); ``` -------------------------------- ### Reading Request Headers Source: https://github.com/serverpod/relic/blob/main/packages/relic/skills/relic-request-response/SKILL.md Examples of how to read various request headers, including common ones like User-Agent and Content-Length, and how to handle authorization headers. ```APIDOC ## Reading Headers ```dart app.get('/info', (req) { final userAgent = req.headers.userAgent; // String? final contentLength = req.headers.contentLength; // int? final mimeType = req.mimeType; // MimeType? // ... }); ``` ### Authorization ```dart app.get('/protected', (req) { final auth = req.headers.authorization; if (auth is BearerAuthorizationHeader) { final token = auth.token; return Response.ok(body: Body.fromString('Token: $token')); } else if (auth is BasicAuthorizationHeader) { final username = auth.username; return Response.ok(body: Body.fromString('User: $username')); } return Response.unauthorized(); }); ``` ``` -------------------------------- ### Serve Directory with Cache Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/08-static-files.md Serves all files from the `_static_files` directory under `/basic/` URLs with 1-day caching. Handles GET and HEAD requests with a tail matching pattern. ```dart server.addRoute( "/basic/**", StaticHandler.directory( "_static_files", serveProtected: true, cacheControl: CacheControlHeader(maxAge: 86400), ), anyOf({Method.get, Method.head}), ); ``` -------------------------------- ### Handling Query Parameters Source: https://github.com/serverpod/relic/blob/main/packages/relic/skills/relic-request-response/SKILL.md Examples of how to access query parameters from the request, both raw and type-safe, including handling missing parameters and custom types. ```APIDOC ## Query Parameters ### Raw Access ```dart app.get('/search', (req) { final query = req.queryParameters.raw['query']; final page = req.queryParameters.raw['page']; return Response.ok(body: Body.fromString('Search: $query, page: $page')); }); ``` ### Typed Query Parameters ```dart const pageParam = IntQueryParam('page'); const limitParam = IntQueryParam('limit'); const priceParam = DoubleQueryParam('price'); app.get('/products', (req) { final page = req.queryParameters.get(pageParam); // int (throws if missing) final limit = req.queryParameters.get(limitParam); // int final maxPrice = req.queryParameters.get(priceParam); // double return Response.ok(body: Body.fromString('page=$page limit=$limit price=$maxPrice')); }); // Nullable variant: final page = req.queryParameters(pageParam); // int? -- null if missing // Custom types: const sortParam = QueryParam('sort', SortOrder.parse); const fromParam = QueryParam('from', DateTime.parse); // Reusable specialization: final class DateTimeQueryParam extends QueryParam { const DateTimeQueryParam(String key) : super(key, DateTime.parse); } ``` ### Multiple Values ```dart app.get('/filter', (req) { final tags = req.url.queryParametersAll['tag'] ?? []; // List return Response.ok(body: Body.fromString('Tags: $tags')); }); // GET /filter?tag=dart&tag=server → Tags: [dart, server] ``` ``` -------------------------------- ### Serve a Directory with Cache Control Source: https://github.com/serverpod/relic/blob/main/packages/relic/skills/relic-static-files/SKILL.md Use a tail pattern (/**) to serve files from a directory with custom cache control headers. This example sets a 1-day cache for all files in the 'public' directory. ```dart app.anyOf( {Method.get, Method.head}, '/static/**', StaticHandler.directory( Directory('public'), cacheControl: (req, fileInfo) => CacheControlHeader(maxAge: 86400), ).asHandler, ); // public/style.css → http://localhost:8080/static/style.css ``` -------------------------------- ### Respond to a POST request on the root route (POST /) Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/03-routing.md Example of using a convenience method to handle POST requests on the root path. This handler will only be invoked for POST requests. ```dart app.post('/', (final Request request) async { return Response.ok(body: Body.fromString('POST request received')); }); ``` -------------------------------- ### Start Server with VM Service Enabled Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/09-hot-reload.md Run your Dart application with the VM service enabled to allow hot reloading. Connect to the provided VM service URL to facilitate the hot reload process. ```bash dart run --enable-vm-service bin/example.dart ``` -------------------------------- ### Status Code Constructors Source: https://github.com/serverpod/relic/blob/main/packages/relic/skills/relic-request-response/SKILL.md Provides examples of common HTTP status code constructors for creating responses. ```APIDOC ## Status Code Constructors ```dart Response.ok(body: Body.fromString('Success')) // 200 Response.noContent() // 204 Response.badRequest(body: Body.fromString('Bad input')) // 400 Response.unauthorized() // 401 Response.notFound() // 404 Response.internalServerError() // 500 Response(418, body: Body.fromString('I am a teapot')) // custom ``` ``` -------------------------------- ### Example: Protected Endpoint with Bearer Token Source: https://context7.com/serverpod/relic/llms.txt Demonstrates authenticating with a Bearer token via curl to the protected endpoint. Shows the expected response indicating successful Bearer authentication. ```bash curl -H "Authorization: Bearer mytoken123" http://localhost:8080/protected # {"message":"Bearer ok","token_len":11} ``` -------------------------------- ### Route-Specific Middleware Application Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/07-middleware.md Illustrates applying middleware to specific route segments. This example applies global logging to all routes and authentication only to routes under the '/api' path. ```dart final app = RelicApp() // Global logging ..use('/', logRequests()) // Authentication only for API routes ..use('/api', authMiddleware()) // Routes ..get('/', homeHandler) // Only logging ..get('/api/users', usersHandler) // Logging + auth ``` -------------------------------- ### Minimal Relic Server Source: https://github.com/serverpod/relic/blob/main/packages/relic/skills/relic-app-setup/SKILL.md A basic Relic server with a GET route for '/hello/:name', a request logger middleware, and a fallback for not found routes. ```dart import 'package:relic/relic.dart'; Future main() async { final app = RelicApp() ..get('/hello/:name', (Request req) { final name = req.rawPathParameters[#name]; return Response.ok( body: Body.fromString('Hello, $name!'), ); }) ..use('/', logRequests()) ..fallback = respondWith( (_) => Response.notFound( body: Body.fromString('Not found'), ), ); await app.serve(); } ``` -------------------------------- ### Basic Authentication Middleware Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/07-middleware.md A basic example of an authentication middleware. Note that changing request.url in middleware does not re-route; use request.forwardTo() for re-routing. ```dart import 'package:serverpod/server.dart'; // Assuming this import is needed // Placeholder for actual middleware implementation Middleware get basicAuthMiddleware => (Session session, Request request) async { // Example: Check for an authorization header final authHeader = request.headers['authorization']; if (authHeader == null || !authHeader.startsWith('Bearer ')) { return Response.unauthorized('Missing or invalid token'); } // If authentication is successful, proceed to the next middleware or handler return await request.next(session); }; ``` -------------------------------- ### Implement Request-Scoped Storage with ContextProperty Source: https://context7.com/serverpod/relic/llms.txt This example demonstrates using `ContextProperty` for type-safe, request-scoped data storage. Middleware can set values, and handlers can retrieve them using a strongly typed API. ```dart import 'dart:developer'; import 'package:relic/relic.dart'; // Define properties as global constants (shared across middleware + handlers) final _requestIdProperty = ContextProperty('requestId'); final _userProperty = ContextProperty('currentUser'); // Convenience extension for clean handler access extension RequestExtensions on Request { String get requestId => _requestIdProperty.get(this); String? get currentUser => _userProperty[this]; // nullable read } // Middleware that stamps a unique ID on each request Handler requestIdMiddleware(Handler next) { return (req) async { _requestIdProperty[req] = 'req_${DateTime.now().millisecondsSinceEpoch}'; return await next(req); }; } // Middleware that authenticates and stores the user in context Middleware authMiddleware() { return (Handler next) { return (Request req) async { final token = req.headers['X-Token']?.first; if (token == null) { return Response.unauthorized(body: Body.fromString('No token')); } // Simulate token → user lookup _userProperty[req] = 'user_from_$token'; return await next(req); }; }; } // Handler reads both context properties Future profileHandler(Request req) async { final reqId = req.requestId; // non-null (set by middleware) final user = req.currentUser; // nullable log('Request $reqId for user $user'); return Response.ok( body: Body.fromString('User: $user (req=$reqId)'), ); } Future main() async { final app = RelicApp() ..use('/', requestIdMiddleware) ..use('/profile', authMiddleware()) ..get('/profile', profileHandler); await app.serve(); } ``` ```bash curl -H "X-Token: abc123" http://localhost:8080/profile ``` -------------------------------- ### Example: Filter with Multi-Value Tags Source: https://context7.com/serverpod/relic/llms.txt Shows a curl request to the filter endpoint with multiple 'tag' parameters. Illustrates how multi-value parameters are received as a list. ```bash curl "http://localhost:8080/filter?tag=dart&tag=server" # {"tags":["dart","server"]} ``` -------------------------------- ### Global Middleware Application Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/07-middleware.md Shows how to apply middleware globally to all routes in a Relic application by using the `use()` method with the root path '/'. This example applies logging and CORS middleware. ```dart final app = RelicApp() // Global middleware - applies to ALL routes ..use('/', logRequests()) ..use('/', corsMiddleware()) // Your routes ..get('/users', usersHandler) ..get('/posts', postsHandler); ``` -------------------------------- ### Respond to a PUT request to the '/user' route Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/03-routing.md Example of using the `.put()` convenience method to handle PUT requests to a specific user route. This is useful for updating user resources. ```dart app.put('/user', (final Request request) async { return Response.ok(body: Body.fromString('PUT request to /user')); }); ``` -------------------------------- ### Relic Application with Multiple Handlers Source: https://context7.com/serverpod/relic/llms.txt Example of a Relic application configured with various handlers for different routes, including synchronous, asynchronous, info, WebSocket, and SSE endpoints, along with a not found fallback. ```dart Future main() async { final app = RelicApp() ..get('/sync', syncHandler) ..get('/async', asyncHandler) ..get('/info', contextInfoHandler) ..get('/ws', webSocketHandler) ..get('/sse', sseHandler) ..fallback = respondWith( (req) => Response.notFound(body: Body.fromString('Not Found')), ); await app.serve(); } ``` -------------------------------- ### Middleware Execution Order Source: https://github.com/serverpod/relic/blob/main/packages/relic/skills/relic-middleware/SKILL.md Middleware executes based on path hierarchy first, then registration order within the same path scope. This example demonstrates the order for a specific route. ```dart final app = RelicApp() ..use('/api', middlewareC) // specific to /api ..use('/', middlewareA) // all paths ..use('/', middlewareB) // all paths ..get('/api/foo', fooHandler); ``` -------------------------------- ### Define Routes with RelicApp Source: https://context7.com/serverpod/relic/llms.txt Use convenience methods like `get`, `post`, `put`, `delete` for common HTTP methods, or the core `add` method for custom methods. Register handlers to process incoming requests. ```dart import 'package:relic/relic.dart'; Future main() async { final app = RelicApp() // Convenience method shortcuts ..get('/', (req) => Response.ok(body: Body.fromString('Hello World!'))) ..post('/', (req) => Response.ok(body: Body.fromString('POST root'))) ..put('/user', (req) => Response.ok(body: Body.fromString('PUT user'))) ..delete('/user', (req) => Response.ok(body: Body.fromString('DELETE user'))) // Core add() method (what convenience methods call internally) ..add(Method.patch, '/api', (req) => Response.ok()) // Multiple methods on one route ..anyOf( {Method.get, Method.post}, '/admin', (req) => Response.ok(body: Body.fromString('Admin: ${req.method.name}')), ) // Named path parameter: access via Symbol key ..get('/users/:id', (req) { final id = req.pathParameters.raw[#id]; return Response.ok(body: Body.fromString('User $id')); }) // Typed path parameters (automatic parsing) ..get('/items/:id/price/:price', (req) { const idParam = IntPathParam(#id); const priceParam = DoublePathParam(#price); final id = req.pathParameters.get(idParam); // int, throws if missing final price = req.pathParameters.get(priceParam); // double return Response.ok(body: Body.fromString('Item $id costs $$price')); }) // Wildcard: matches any single segment, value not captured ..get('/files/*/download', (req) => Response.ok(body: Body.fromString('Downloading...'))) // Tail segment: captures the remainder of the path ..get('/static/**', (req) { final relativePath = req.remainingPath.toString(); return Response.ok(body: Body.fromString('Serve: $relativePath')); }) // Internal request forwarding (re-routes through the same router) ..get('/v1/users', (req) { final newReq = req.copyWith(url: req.url.replace(path: '/v2/users')); return req.forwardTo(newReq); }) ..get('/v2/users', (req) => Response.ok(body: Body.fromString('v2 users list'))); await app.serve(); } ``` -------------------------------- ### Hello World Server Implementation Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/01-getting-started/02-hello-world-example.md This code sets up a Relic application with a /user route that accepts name and age parameters. It also includes middleware for logging requests and a fallback for handling unmatched routes. ```dart import 'package:relic/relic.dart'; Future main() async { final app = RelicApp(); // Log all requests app.use('/', logRequests()); // Define a route that accepts parameters app.get('/user/name/:name/age/:age', (RequestContext context) async { final name = context.params['name']; final age = context.params['age']; return Response.ok('Hello $name! To think you are $age years old.'); }); // Fallback for unmatched routes app.fallback((_) => Response.notFound('Not found')); // Start the server on port 8080 await app.serve(port: 8080); print('Server listening on port 8080'); } ``` -------------------------------- ### Bootstrap Server: Shelf vs Relic Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/01-getting-started/03-shelf-migration.md Replace `shelf_io.serve()` with `RelicApp().serve()` for bootstrapping the server. ```dart import 'package:shelf_router/shelf_router.dart'; import 'package:shelf/shelf.dart'; import 'package:shelf/shelf_io.dart' as io; void main() async { final app = Router(); // Add routes... await io.serve(app, 'localhost', 8080); } ``` ```dart import 'package:relic/relic.dart'; void main() async { final app = RelicApp(); // Add routes... await app.serve(port: 8080); } ``` -------------------------------- ### Hello World Relic Server Source: https://github.com/serverpod/relic/blob/main/packages/relic/README.md A basic 'Hello World' server demonstrating Relic's routing, middleware, and response handling. It includes a route with path parameters and a custom fallback handler. ```dart import 'package:relic/io_adapter.dart'; import 'package:relic/relic.dart'; /// A simple 'Hello World' server demonstrating basic Relic usage. Future main() async { // Setup the app. final app = RelicApp() // Route with parameters (:name & :age). ..get('/user/:name/age/:age', helloHandler) // Middleware on all paths below '/'. ..use('/', logRequests()) // Custom fallback - optional (default is 404 Not Found). ..fallback = respondWith( (_) => Response.notFound( body: Body.fromString("Sorry, that doesn't compute.\n"), ), ); // Start the server (defaults to using port 8080). await app.serve(); } const _ageParam = PathParam(#age, int.parse); /// Handles requests to the hello endpoint with path parameters. Response helloHandler(final Request req) { final name = req.pathParameters.raw[#name]; final age = req.pathParameters.get(_ageParam); return Response.ok( body: Body.fromString('Hello, $name! To think you are $age years old.\n'), ); } ``` -------------------------------- ### Add GET route to root '/' Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/03-routing.md A convenience method for adding a GET route to the root path. This is commonly used for the homepage. ```dart router.add(Method.get, '/', handler); ``` -------------------------------- ### Add GET route to '/my/path' Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/03-routing.md Defines a route that responds to GET requests on a specific path. The handler function is executed when the route matches. ```dart router.add(Method.get, '/my/path', myHandler); // Or, with a convenience method: router.get('/my/path', myHandler); ``` -------------------------------- ### Conventional Commit Message Example Source: https://github.com/serverpod/relic/blob/main/CONTRIBUTING.md Use a conventional commit message format for clarity and to aid automated changelog generation. This example shows a feature commit for the router. ```git feat(router): add support for wildcard routes ``` -------------------------------- ### Add New Documentation Version Source: https://github.com/serverpod/relic/blob/main/doc/site/README.md Use 'make version X.X.X' to add a new version to the documentation. Ensure documentation is up-to-date before running. ```bash make version X.X.X ``` -------------------------------- ### Custom Status Code Response Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/05-responses.md Example of creating a response with a custom HTTP status code. ```APIDOC ## Custom Status Code Response ### Description Creates a response with a specific, non-standard HTTP status code. ### Method Implicitly handled by the framework when returning a `Response` object with a specified status code. ### Endpoint N/A (Framework specific) ### Response #### Custom Response (e.g., 201 Created) - **Status Code** (integer) - The custom status code (e.g., 201). - **Body** (any) - The response body content. ### Response Example ```json { "message": "Resource created successfully." } ``` ``` -------------------------------- ### POST / Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/03-routing.md Respond to a POST request on the root route using the convenience POST method. ```APIDOC ## POST / ### Description Handles POST requests to the root path. ### Method POST ### Endpoint / ### Request Example (No request body specified) ### Response #### Success Response (200) (No response body specified) ``` -------------------------------- ### 400 Bad Request JSON Error Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/05-responses.md Example of creating a JSON error response for a bad request. ```APIDOC ## 400 Bad Request JSON Error ### Description Returns a JSON error response indicating a bad request. ### Method Implicitly handled by the framework when returning a `Response` object with a JSON body and a 400 status. ### Endpoint N/A (Framework specific) ### Response #### Error Response (400) - **Content-Type** (string) - `application/json` - **Body** (object) - Contains error details. - **error** (string) - A message describing the error. ### Response Example ```json { "error": "Invalid input data." } ``` ``` -------------------------------- ### 200 OK Text Response Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/05-responses.md Example of creating a basic success response with plain text content. ```APIDOC ## 200 OK Text Response ### Description Creates a success response with a plain text body. ### Method Implicitly handled by the framework when returning a String. ### Endpoint N/A (Framework specific) ### Response #### Success Response (200) - **Content-Type** (string) - `text/plain` - **Body** (string) - The plain text content. #### Response Example ``` Hello, World! ``` ``` -------------------------------- ### Connection Hijacking for SSE Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/01-handlers.md Example of a handler that hijacks the connection to implement Server-Sent Events (SSE). ```dart Future handler(Request req) async { return Hijack( (stream) async { // Simulate sending SSE events for (int i = 0; i < 5; i++) { await stream.write("event: message\n"); await stream.write("data: SSE event $i\n\n"); await Future.delayed(Duration(seconds: 1)); } await stream.close(); }, ); } ``` -------------------------------- ### Create a new Dart package Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/01-getting-started/02-hello-world-example.md Use this command to create a new Dart console-full project. ```bash dart create -t console-full hello_world ``` -------------------------------- ### WebSocket Echo Handler Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/01-handlers.md Example of a handler that upgrades the connection to a WebSocket and echoes messages back to the client. ```dart Future handler(Request req) async { return WebSocketUpgrade.create( upgrade: (webSocket) async { await webSocket.stream.forEach((message) async { await webSocket.sink.add(message); }); }, ); } ``` -------------------------------- ### Method Enum Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/04-requests.md The Method enum defines standard HTTP methods (e.g., GET, POST, PUT) for use in requests. ```APIDOC ## Method Enum ### Description Enumeration of HTTP methods. ### Link https://pub.dev/documentation/relic/latest/relic/Method.html ``` -------------------------------- ### Run markdownlint Source: https://github.com/serverpod/relic/blob/main/doc/site/README.md Execute markdownlint-cli within the './doc/site/' directory to check markdown file formatting. ```bash $ markdownlint './doc/site/**/*.md' ``` -------------------------------- ### Create a new Dart console app Source: https://github.com/serverpod/relic/blob/main/packages/relic_core/README.md Scaffold a new Dart console application to begin building your Relic server. ```bash dart create -t console-full hello_world cd hello_world dart pub add relic ``` -------------------------------- ### Clone the Relic Repository Source: https://github.com/serverpod/relic/blob/main/CONTRIBUTING.md Clone your forked repository locally to start making changes. Ensure you replace YOUR_USERNAME with your actual GitHub username. ```bash git clone https://github.com/YOUR_USERNAME/relic.git ``` -------------------------------- ### Migration from Pipeline to router.use() Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/99-pipeline.md Compares the old Pipeline approach with the new router.use() approach for middleware composition. The new approach is more concise and integrates better with Relic's routing. ```dart final handler = Pipeline().addMiddleware(logRequests).addHandler(myHandler); ``` ```dart final router = Router() ..middleware(logRequests) ..get("/", myHandler); ``` -------------------------------- ### Define Synchronous and Asynchronous Handlers Source: https://context7.com/serverpod/relic/llms.txt Examples of creating synchronous and asynchronous handlers for processing requests. Asynchronous handlers can use 'await' for non-blocking operations. ```dart // Synchronous handler Response syncHandler(Request req) => Response.ok(body: Body.fromString('Fast response')); // Asynchronous handler Future asyncHandler(Request req) async { final data = await Future.delayed( const Duration(milliseconds: 250), () => 'Hello from Relic!', ); return Response.ok(body: Body.fromString(data)); } ``` -------------------------------- ### Enable Hot Reload via CLI Source: https://github.com/serverpod/relic/blob/main/packages/relic/skills/relic-app-setup/SKILL.md Run the server with the VM service enabled to allow for hot reloading of route handlers without a full restart. ```bash dart run --enable-vm-service bin/main.dart ``` -------------------------------- ### Serve Single File Source: https://github.com/serverpod/relic/blob/main/doc/site/docs/02-reference/08-static-files.md Serves a specific individual file, useful for resources like favicons or robots.txt. ```dart server.addRoute( "/favicon.ico", StaticHandler.file("assets/favicon.ico"), ); ``` -------------------------------- ### Reading the Request Body Source: https://github.com/serverpod/relic/blob/main/packages/relic/skills/relic-request-response/SKILL.md Demonstrates different methods for reading the request body, including as a string, JSON, or a byte stream, with examples for size-limited reads. ```APIDOC ## Reading the Request Body The body can only be read once. A second read throws `StateError`. ### As String ```dart app.post('/submit', (req) async { final text = await req.readAsString(); return Response.ok(body: Body.fromString('Received: $text')); }); ``` ### JSON Parsing ```dart app.post('/api/users', (req) async { try { final body = await req.readAsString(); final data = jsonDecode(body) as Map; final name = data['name'] as String?; final email = data['email'] as String?; if (name == null || email == null) { return Response.badRequest( body: Body.fromString( jsonEncode({'error': 'Name and email are required'}, mimeType: MimeType.json, ), ); } return Response.ok( body: Body.fromString( jsonEncode({'message': 'User created', 'name': name}), mimeType: MimeType.json, ), ); } catch (e) { return Response.badRequest( body: Body.fromString(jsonEncode({'error': 'Invalid JSON: $e'}), mimeType: MimeType.json), ); } }); ``` ### Byte Stream ```dart app.post('/upload', (req) async { if (req.isEmpty) { return Response.badRequest(body: Body.fromString('Body required')); } final stream = req.read(); // Stream int totalBytes = 0; await for (final chunk in stream) { totalBytes += chunk.length; } return Response.ok(body: Body.fromString('Received $totalBytes bytes')); }); ``` ### Size-Limited Reads ```dart const maxFileSize = 10 * 1024 * 1024; // 10 MB final sink = file.openWrite(); try { await sink.addStream(req.read(maxLength: maxFileSize)); } on MaxBodySizeExceeded { return Response.badRequest(body: Body.fromString('File too large')); } finally { await sink.close(); } ``` ``` -------------------------------- ### Core `add()` Method Source: https://context7.com/serverpod/relic/llms.txt Use the core `add()` method to register routes for any HTTP method. ```APIDOC ## PATCH /api ### Description Handles PATCH requests to the /api path using the core `add` method. ### Method PATCH ### Endpoint /api ### Request Example (No request body specified) ### Response #### Success Response (200) (No specific response fields documented) ### Response Example (No example provided) ```