Spaces:
Running
Running
| # Middleware in FastAPI | |
| Middleware is a function that processes every request before it reaches a route handler and every response before it is returned to the client. FastAPI supports both ASGI middleware (from Starlette) and its own decorator-based middleware. | |
| ## Custom Middleware | |
| Use the `@app.middleware("http")` decorator to create custom middleware: | |
| ```python | |
| import time | |
| from fastapi import FastAPI, Request | |
| app = FastAPI() | |
| @app.middleware("http") | |
| async def add_process_time_header(request: Request, call_next): | |
| start_time = time.perf_counter() | |
| response = await call_next(request) | |
| process_time = time.perf_counter() - start_time | |
| response.headers["X-Process-Time"] = f"{process_time:.4f}" | |
| return response | |
| ``` | |
| The middleware receives the incoming `Request` object and a `call_next` function. Calling `await call_next(request)` passes the request to the next middleware or route handler in the chain and returns the `Response`. You can modify both the request (before `call_next`) and the response (after `call_next`). | |
| ## CORS Middleware | |
| Cross-Origin Resource Sharing (CORS) is configured using `CORSMiddleware` from Starlette: | |
| ```python | |
| from fastapi import FastAPI | |
| from fastapi.middleware.cors import CORSMiddleware | |
| app = FastAPI() | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["https://example.com", "https://app.example.com"], | |
| allow_credentials=True, | |
| allow_methods=["GET", "POST", "PUT", "DELETE"], | |
| allow_headers=["Authorization", "Content-Type"], | |
| expose_headers=["X-Custom-Header"], | |
| max_age=600, | |
| ) | |
| ``` | |
| The `CORSMiddleware` parameters: | |
| | Parameter | Default | Description | | |
| |----------------------|---------|----------------------------------------------------| | |
| | `allow_origins` | `[]` | List of allowed origin URLs | | |
| | `allow_origin_regex` | `None` | Regex pattern for matching allowed origins | | |
| | `allow_methods` | `["GET"]` | HTTP methods allowed for cross-origin requests | | |
| | `allow_headers` | `[]` | HTTP headers allowed in cross-origin requests | | |
| | `allow_credentials` | `False` | Whether cookies are permitted in cross-origin requests | | |
| | `expose_headers` | `[]` | Response headers accessible to the browser | | |
| | `max_age` | `600` | Seconds the browser caches preflight results | | |
| To allow all origins, use `allow_origins=["*"]`. However, when `allow_credentials=True`, you cannot use the wildcard `"*"` for `allow_origins` -- you must list specific origins. This is a CORS specification requirement, not a FastAPI limitation. | |
| ## Middleware Ordering | |
| Middleware executes in reverse order of how it is added. The last middleware added is the first to process the request (outermost layer): | |
| ```python | |
| app = FastAPI() | |
| @app.middleware("http") | |
| async def middleware_one(request: Request, call_next): | |
| print("Middleware 1: before") # Runs second | |
| response = await call_next(request) | |
| print("Middleware 1: after") # Runs third | |
| return response | |
| @app.middleware("http") | |
| async def middleware_two(request: Request, call_next): | |
| print("Middleware 2: before") # Runs first | |
| response = await call_next(request) | |
| print("Middleware 2: after") # Runs fourth | |
| return response | |
| ``` | |
| The output order for a request is: `Middleware 2: before`, `Middleware 1: before`, (route handler), `Middleware 1: after`, `Middleware 2: after`. This follows the standard "onion" model where each middleware wraps the next layer. | |
| ## Trusted Host Middleware | |
| Protect against HTTP Host header attacks: | |
| ```python | |
| from fastapi.middleware.trustedhost import TrustedHostMiddleware | |
| app.add_middleware( | |
| TrustedHostMiddleware, | |
| allowed_hosts=["example.com", "*.example.com"], | |
| ) | |
| ``` | |
| Requests with a `Host` header not matching the allowed hosts receive a 400 Bad Request response. | |
| ## GZip Middleware | |
| Compress responses automatically when the client supports it: | |
| ```python | |
| from fastapi.middleware.gzip import GZipMiddleware | |
| app.add_middleware(GZipMiddleware, minimum_size=500) | |
| ``` | |
| The `minimum_size` parameter (default: `500` bytes) sets the minimum response body size before compression is applied. Responses smaller than this threshold are sent uncompressed. GZip compression typically reduces JSON response sizes by 60-80%. | |
| ## ASGI Middleware | |
| Since FastAPI is an ASGI application, you can use any ASGI-compatible middleware: | |
| ```python | |
| from starlette.middleware.sessions import SessionMiddleware | |
| app.add_middleware( | |
| SessionMiddleware, | |
| secret_key="your-session-secret", | |
| max_age=14 * 24 * 60 * 60, # 14 days in seconds = 1,209,600 | |
| ) | |
| ``` | |
| The `add_middleware()` method is the preferred way to add middleware in FastAPI, as it ensures proper integration with the application's middleware stack and exception handling. | |