FastAPI Request Lifecycle — Diagrams¶
Overview¶
These diagrams trace the full journey of an HTTP request through a FastAPI application, from the ASGI server accepting the connection to the JSON response leaving the wire.
Request Flow Through the Stack¶
Every FastAPI request passes through several layers before your endpoint function runs. Understanding this stack helps you debug middleware issues, dependency failures, and response timing.
flowchart TD
CLIENT["Client sends HTTP request"] --> UVICORN["Uvicorn (ASGI Server)<br/>Accepts TCP connection"]
UVICORN --> MIDDLEWARE["Middleware Stack<br/>CORS, TrustedHost, GZip"]
MIDDLEWARE --> ROUTER["APIRouter<br/>Match path + method"]
ROUTER --> DEPS["Dependency Injection<br/>Depends() resolved"]
DEPS --> VALIDATE["Pydantic Validation<br/>Parse body, query, path params"]
VALIDATE --> ENDPOINT["Your Endpoint Function<br/>async def create_user(...)"]
ENDPOINT --> RESPONSE["Build Response<br/>Serialize with Pydantic model"]
RESPONSE --> MIDDLEWARE2["Middleware (response phase)<br/>Add headers, logging"]
MIDDLEWARE2 --> CLIENT2["Client receives response"]
style UVICORN fill:#4a9eff,stroke:#2670c2,color:#fff
style MIDDLEWARE fill:#ffd43b,stroke:#f59f00,color:#000
style ROUTER fill:#cc5de8,stroke:#9c36b5,color:#fff
style DEPS fill:#ff922b,stroke:#e8590c,color:#fff
style VALIDATE fill:#51cf66,stroke:#27ae60,color:#fff
style ENDPOINT fill:#51cf66,stroke:#27ae60,color:#fff
style RESPONSE fill:#4a9eff,stroke:#2670c2,color:#fff
Key points: - Uvicorn is the ASGI server that translates raw TCP into Python async calls - Middleware runs twice: once on the way in, once on the way out - Dependency injection resolves before your function body executes - Pydantic validates and converts all input data automatically
Dependency Injection Chain¶
FastAPI's Depends() system lets you build reusable chains of setup logic. Dependencies can depend on other dependencies, forming a tree that resolves from leaves to root.
flowchart TD
EP["Endpoint Function<br/>async def get_items(db, user)"] --> DEP_DB["Depends(get_db)<br/>Open database session"]
EP --> DEP_USER["Depends(get_current_user)<br/>Validate JWT, return User"]
DEP_USER --> DEP_TOKEN["Depends(oauth2_scheme)<br/>Extract Bearer token from header"]
DEP_DB --> YIELD_DB["yield db<br/>--- endpoint runs ---<br/>db.close()"]
DEP_TOKEN --> DECODE["Decode JWT<br/>Query user from DB"]
subgraph LIFECYCLE ["Dependency Lifecycle"]
direction LR
RESOLVE["1. Resolve tree<br/>leaf-first"] --> INJECT["2. Inject into<br/>endpoint params"] --> CLEANUP["3. Run yield<br/>cleanup code"]
end
style EP fill:#cc5de8,stroke:#9c36b5,color:#fff
style DEP_DB fill:#ff922b,stroke:#e8590c,color:#fff
style DEP_USER fill:#ff922b,stroke:#e8590c,color:#fff
style DEP_TOKEN fill:#ffd43b,stroke:#f59f00,color:#000
style LIFECYCLE fill:#51cf66,stroke:#27ae60,color:#fff
Key points:
- Dependencies form a tree resolved bottom-up (leaves first)
- yield dependencies run setup code, then cleanup after the endpoint finishes
- The same dependency used twice in one request is resolved only once (cached)
- Dependency injection replaces global variables with testable, swappable components
Sequence: Authentication + Database Request¶
A realistic sequence showing how a protected endpoint handles a request from token validation through database access to JSON response.
sequenceDiagram
participant C as Client
participant U as Uvicorn
participant M as Middleware
participant R as Router
participant D as Dependencies
participant E as Endpoint
participant DB as Database
C->>U: POST /items<br/>Authorization: Bearer <token><br/>Body: {"name": "Widget"}
U->>M: ASGI scope + receive
M->>R: Route lookup
R->>D: Resolve Depends(get_db)
D->>DB: Open session
DB-->>D: Session ready
R->>D: Resolve Depends(get_current_user)
Note over D: Decode JWT, validate
D-->>R: user=User(id=7)
R->>E: create_item(db=session, user=user, item=Item(name="Widget"))
Note over E: Pydantic already validated body
E->>DB: INSERT INTO items ...
DB-->>E: New row (id=42)
E-->>R: ItemResponse(id=42, name="Widget")
R-->>M: JSONResponse(status=201)
M-->>U: Add CORS headers
U-->>C: HTTP/1.1 201 Created<br/>{"id": 42, "name": "Widget"}
Note over D: Cleanup: db.close()
Key points: - Authentication happens in the dependency layer, not in your endpoint code - Pydantic validates the request body before the endpoint function is called - Database session cleanup runs after the response is built (yield dependency) - The endpoint only contains business logic, everything else is handled by the framework
| Back to Diagram Index |
|---|