FastAPI Routing, Parameters, Bodies & Response Models

FastAPI is built on top of Starlette (for ASGI web routing) and Pydantic (for data validation and serialization). Unlike traditional web frameworks that parse requests and validate types using dynamic Python code in middleware, FastAPI constructs an internal route dispatch graph at application startup, generating OpenAPI schemas and Pydantic validators for every path operation.

This chapter details Starlette’s ASGI route matching engine, request parameter extraction mechanics, and Pydantic response filtering.


1. Starlette ASGI Routing Engine Architecture

FastAPI extends starlette.routing.Router. When an application starts, FastAPI iterates over all registered routes (@app.get(), APIRouter) and compiles them into a tree of Route and WebSocketRoute objects.

FastAPI Request Routing Pipeline:

[ Incoming ASGI HTTP Request (scope, receive, send) ]
                        |
                        v
[ Starlette Router (Matching Path & HTTP Method) ]
                        |
                        v
[ Route Match Found: Extract Path Params (e.g. user_id=42) ]
                        |
                        v
[ FastAPI Dependant Runner (Solve Dependencies & Validate Query/Body) ]
                        |
                        v
[ Execute Path Operation Function (async def or def) ]
                        |
                        v
[ Pydantic Response Model Serialization & Filtering ]
                        |
                        v
[ Starlette JSONResponse (Send ASGI Response Bytes) ]

2. Parameter Extraction Mechanics (Path, Query, Body)

FastAPI uses Python type annotations and default marker objects (Path(), Query(), Header(), Body()) to inspect functions using inspect.signature().

During startup, FastAPI’s get_param_sub_dependant() analyzes function parameters:

  • Path Parameters: Declared in the URL path (/users/{user_id}). FastAPI validates them as required.
  • Query Parameters: Scalar types (int, str) not present in the URL path are automatically extracted from URL query strings.
  • Request Body: Complex Pydantic models or Body() parameters instruct FastAPI to read and parse the incoming JSON payload from the ASGI receive channel.

3. Pydantic Response Model Filtering (response_model)

Setting response_model=UserResponse on a route decorator instructs FastAPI to perform two critical tasks:

  1. Schema Generation: Exports UserResponse to the OpenAPI specification.
  2. Data Sanitization & Filtering: Passes the return value of the view function through fastapi.encoders.jsonable_encoder() and validates it against UserResponse. Any attributes in the ORM or dict return value that are not declared in UserResponse (such as hashed_password or internal_flags) are automatically stripped from the outgoing JSON response.
Response Filtering Flow:

[ View Returns ORM User Object (contains hashed_password) ]
                         |
                         v
[ FastAPI Response Serialization Engine ]
                         |
                         v
[ Filters payload using UserResponse Pydantic Schema ]
                         |
                         v
[ Outgoing JSON: {"id": 1, "email": "user@example.com"} ]
(hashed_password is safely stripped!)

4. Production Trade-offs & Router Modularization

  • APIRouter Modularization: Divide applications into logical feature modules using APIRouter(prefix="/api/v1/users", tags=["Users"]).
  • Response Model Overhead: For ultra-low latency endpoints (sub-5ms SLA), passing ORM objects through complex response_model validation adds a minor Pydantic serialization overhead. For extreme performance, return JSONResponse directly or use Pydantic V2 TypeAdapter.
Display Options
Appearance
Text Size
100%