Learning outcomes
- Build custom ASGI HTTP middlewares
- Track correlation IDs safely with ContextVars
Mental model
FastAPI middleware is an outer ASGI wrapper around your application, executing onion-style before and after every HTTP request.
Theory
Custom middlewares can be implemented via @app.middleware("http") or pure ASGI class wrappers (BaseHTTPMiddleware). Middlewares are ideal for cross-cutting concerns: setting unique X-Request-ID correlation headers, logging request duration, handling global CORS policies, and scoping thread-safe request state using Python contextvars.ContextVar.
import time
import uuid
from contextvars import ContextVar
from fastapi import FastAPI, Request
request_id_var: ContextVar[str] = ContextVar("request_id", default="")
app = FastAPI()
@app.middleware("http")
async def add_correlation_id_and_timing(request: Request, call_next):
correlation_id = request.headers.get("X-Request-ID", str(uuid.uuid4()))
token = request_id_var.set(correlation_id)
start_time = time.perf_counter()
response = await call_next(request)
duration_ms = (time.perf_counter() - start_time) * 1000
response.headers["X-Request-ID"] = correlation_id
response.headers["X-Process-Time-MS"] = f"{duration_ms:.2f}"
request_id_var.reset(token)
return response
@app.get("/health")
async def health_check():
return {"status": "ok", "correlation_id": request_id_var.get()}
Alternatives and trade-offs
- Middlewares: Run globally on every request (CORS, timing, request ID).
- FastAPI Dependencies: Run only on targeted routes and support
Dependsgraph composition.
Failure modes and misconceptions
BaseHTTPMiddlewareStreaming Issues:BaseHTTPMiddlewarebuffers responses in memory and can break SSE / WebSocket streaming.- ContextVar Leaks: Always reset
ContextVartokens infinallyblocks when reusing threads across requests.
Decision scenario
Use @app.middleware("http") for application-wide request logging and correlation headers. Use route-level Depends for granular authentication and authorization checks.
Learning outcomes
- Build HTTP middlewares for correlation tracing and latency logging.
- Store context-local state safely across async tasks using
contextvars.ContextVar. - Avoid response buffering issues with high-throughput streaming endpoints.
Trade-offs
Global middlewares execute on every incoming HTTP request path, so middleware logic must stay extremely fast and lightweight.
Evidence assessment
Theory and decision mastery
Decision scenario
An API team needs to inject a unique X-Request-ID header into every HTTP response and log request duration.
What is the most idiomatic FastAPI implementation?
Primary sources
- FastAPI Framework Architecture & Dependency Injection Specification — Tiangolo, verified 2026-07-22