
Middleware and the Request Lifecycle
Understand the 'Gatekeepers' of your API. Learn what middleware is, how it executes, and the order of operations in a FastAPI request.
Middleware and the Request Lifecycle
Think of Middleware as a series of "Filter Layers" through which every request must pass before it reaches your code, and through which every response must pass before it reaches the user.
In this lesson, we demystify the "Gatekeepers" of FastAPI.
1. What is Middleware?
Middleware is a function that works with every request before it is processed by any specific path operation. And also with every response before returning it.
The Lifecycle of a Middleware Request:
- Incoming Request arrives from the user.
- Middleware A processes it (e.g., checks for a valid IP).
- Middleware B processes it (e.g., starts a timer).
- Your Path Operation runs (e.g.,
get_users). - Middleware B processes the result (e.g., logs how long it took).
- Middleware A processes the result (e.g., adds security headers).
- Response is sent to the user.
2. When to Use Middleware
If you need a piece of code to run for EVERY route in your app, use Middleware. If it only needs to run for some routes, use Dependency Injection.
Common Middleware Tasks:
- Logging: Record every URL visited.
- CORS: Allow or block requests from specific websites.
- Authentication: Verify a session cookie globally.
- Compression: Gzip the response to make it smaller/faster.
- Custom Headers: Add
X-Process-Timeto every response.
3. The Middleware Decorator
FastAPI (via Starlette) provides a simple @app.middleware("http") decorator.
import time
from fastapi import Request
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
# --- Code here runs BEFORE your route function ---
start_time = time.time()
# This line triggers the route logic!
response = await call_next(request)
# --- Code here runs AFTER your route function ---
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
return response
4. Execution Order
Middleware follows an "Onion" architecture.
- The First middleware you add is the Outer Layer (runs first on request, last on response).
- The Last middleware you add is the Inner Layer (runs last on request, first on response).
Visualizing the Onion
graph TD
A["Request"] --> B["CORS Middleware"]
B --> C["Logging Middleware"]
C --> D["Your FastAPI Function"]
D --> E["Logging Middleware (Cleanup)"]
E --> F["CORS Middleware (Final Headers)"]
F --> G["Response"]
Summary
- Middleware is global—it runs for every request.
call_next: The critical bridge that hands the request to the rest of your app.- The Onion: Understand that middleware wraps your code on both sides (Inbound and Outbound).
In the next lesson, we’ll look at Common Middleware Use Cases: Logging, CORS, and Rate Limiting.
Exercise: The Security Guard
Imagine you want to block all requests that don't have a specific header X-Environment: production. Why is Middleware a better place for this check than a standard Dependency?