Advanced: Middleware & Request Lifecycle
The API server uses a layered middleware architecture to handle requests. Middleware are functions that process a request before it reaches its final destination (the route handler). This approach allows for the separation of concerns like logging, authentication, and error handling from the core business logic.
An incoming request flows through a series of middleware in an “onion-skin” fashion. The outermost middleware runs first, and the innermost middleware runs last, just before the route handler.
The Middleware Chain
Section titled “The Middleware Chain”The server defines middleware at different levels of the route tree. Here’s a breakdown of the key middleware and where they are applied:
-
Root Middleware (
/routes/_middleware.dart
):errorHandler
: The final safety net that catches all exceptions and formats them into standard JSON error responses.requestLogger
: Logs details of every incoming request.requestIdProvider
: Assigns a unique ID to each request for tracing.dependencyProvider
: Initializes and injects all application-wide dependencies (repositories, services, registries) into the request context.
-
API v1 Middleware (
/routes/api/v1/_middleware.dart
):corsHeaders
: Applies Cross-Origin Resource Sharing (CORS) headers to responses.authenticationProvider
: Validates theBearer
token and injects aUser
object (ornull
) into the context.
-
Data Route Group Middleware (
/routes/api/v1/data/_middleware.dart
):requireAuthentication
: Aborts the request if no authenticated user is found._dataRateLimiterMiddleware
: Applies rate limiting based on the user’s ID._modelValidationAndProviderMiddleware
: Validates the?model=
query parameter and injects theModelConfig
and model name into the context.authorizationMiddleware
: Performs high-level permission checks based on theModelConfig
.
-
Item-Specific Middleware (
/routes/api/v1/data/[id]/_middleware.dart
):dataFetchMiddleware
: Fetches the specific item by its ID and injects it into the context.ownershipCheckMiddleware
: Verifies if the authenticated user is the owner of the fetched item, if required by theModelConfig
.