fastapi/fastapi
Routing
Purpose
fastapi/routing.py (4,956 lines) is where path-operation decorators turn into ASGI handlers. It defines APIRouter, the route classes (APIRoute for HTTP, APIWebSocketRoute for WebSockets), the request/response wrappers that integrate with the dependency system, and the response serializer.
Directory layout
fastapi/
├── routing.py # APIRouter, APIRoute, APIWebSocketRoute, helpers
├── dependencies/
│ ├── models.py # Dependant dataclass
│ └── utils.py # solve_dependencies, get_dependant
├── middleware/
│ └── asyncexitstack.py # AsyncExitStackMiddleware
└── exception_handlers.py # default handlersKey abstractions
| Symbol | Description |
|---|---|
APIRouter |
A starlette.routing.Router subclass that adds add_api_route, add_api_websocket_route, include_router, dependency-with-prefix support, and helper decorators (.get, .post, .put, .patch, .delete, .options, .head, .trace, .api_route, .websocket). |
APIRoute |
Subclass of starlette.routing.Route. Holds the endpoint, the response model, the response class, the status code, dependencies, OpenAPI metadata, and a compiled Dependant tree. Builds an ASGI app from the endpoint via request_response. |
APIWebSocketRoute |
Same as APIRoute but for WebSockets. Uses the websocket_session wrapper. |
request_response(func) |
Wraps a function into an ASGI app. Sets up the two request-scoped AsyncExitStacks on the scope, invokes the user's function, and runs the response. Raises a verbose FastAPIError if a yield-style dependency swallowed an exception. |
serialize_response(...) |
Validates a return value against the route's response_model (or its return-type annotation), then either returns the validated value or — when response_class is JSON-capable and a model is set — dumps it directly to JSON bytes for speed. |
_endpoint_context_cache |
Module-level cache keyed on id(func); populated by _extract_endpoint_context to cache file/line/name lookups. The cache is read in the validation-error paths so error messages can name the offending endpoint. |
_DefaultLifespan |
Vendored copy of the Starlette class that runs on_startup and on_shutdown. Starlette removed it (see PR ref in the comment); FastAPI keeps it for backward compatibility. |
How it works
graph TD
Decorator["@router.get(path)"] --> AddRoute["APIRouter.add_api_route"]
AddRoute --> Construct["APIRoute(path, endpoint, ...)"]
Construct --> BuildDep["get_dependant(call=endpoint, ...)"]
BuildDep --> Dependant["Dependant tree"]
Construct --> Wrap["request_response(get_route_handler())"]
Wrap --> ASGIApp["ASGI app stored on the route"]
ASGIApp -->|on request| Solve["solve_dependencies(request, dependant, ...)"]
Solve -->|values, errors| Endpoint["endpoint(**values)"]
Endpoint --> Serialize["serialize_response(...)"]
Serialize --> Response["Response (JSON / stream / bytes)"]APIRoute.get_route_handler() returns the inner async function that:
- Reads the request body once (handing form/multipart data to
python-multipartwhen relevant). - Walks the route's
Dependantviasolve_dependencies. - Calls the endpoint (sync endpoints go through
run_in_threadpool). - If the endpoint returned a
Responseinstance, sends it as-is. Otherwise callsserialize_responseand wraps the result in the route'sresponse_class.
include_router(other, prefix="/api/v1", dependencies=[...], tags=[...], responses={...}) merges another router. It walks the sub-router's routes, prepends the prefix, concatenates dependencies and tags, deep-merges the responses dict (fastapi/utils.py:deep_dict_update), and registers each child route on the parent.
Routing for Server-Sent Events
For response_class=EventSourceResponse (fastapi/sse.py), the path operation function is expected to be an async generator yielding ServerSentEvent objects, plain dicts, Pydantic models, or None for keep-alive ticks. The routing layer detects the SSE response class and switches into the SSE encoding path (format_sse_event from fastapi/sse.py), with a 15-second keep-alive (_PING_INTERVAL) that emits : ping comments to keep proxies from idling out. Any HTTP method works, including POST, which makes the implementation MCP-compatible. See Server-Sent Events for the full picture.
Integration points
- Up to
FastAPI—FastAPI.routeris anAPIRouter. Decorators onFastAPIforward here. - Down to
dependencies/—get_dependantis called once at registration;solve_dependenciesruns on every request. - Down to
_compat—serialize_responseusesModelField.serializefromfastapi/_compat/v2.pyfor fast JSON dumps. - Down to
openapi/utils.py— the schema generator inspects everyAPIRouteto build the OpenAPI document.
Entry points for modification
- New decorator (e.g. a verb): add a thin method to
APIRoutermirroring.get, then mirror it onFastAPI. - New per-route option: add it to
APIRoute.__init__, plumb it throughadd_api_route,add_api_websocket_route(where relevant),include_router, and theFastAPIdecorators. - Changing serialization defaults: modify
serialize_response. Keep the Pydantic-fast-path branch; tests undertests/test_dump_json_fast_path.pycover it. - Diagnostics: extend
EndpointContext(fastapi/exceptions.py) or_extract_endpoint_contextto add new metadata; the validation errors will surface it automatically.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.
Previous
Application core
Next
Parameters