agentbench / data /tech_docs /fastapi_middleware.md
Nomearod's picture
feat: Day 4 — corpus, ingest script, first 10 golden questions
a152b95

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:

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:

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):

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:

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:

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:

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.