← Docs

FastAPI Patterns

Production-grade recipes for dependency injection, middleware, and structured responses.

Dependency Injection

Use Depends() to inject database sessions, auth contexts, and configuration. Keep route handlers thin — business logic lives in service layers, never in path operation functions.

from fastapi import Depends
from sqlalchemy.ext.asyncio import AsyncSession

async def get_db():
    async with async_session() as session:
        yield session

@router.get("/items")
async def list_items(db: AsyncSession = Depends(get_db)):
    return await item_service.get_all(db)

Middleware Stack

Chain CORS, timing, and request-ID middleware via app.add_middleware(). Order matters — outermost middleware runs first on ingress and last on egress.

from starlette.middleware.base import BaseHTTPMiddleware
import time, uuid

class TimingMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        request.state.request_id = str(uuid.uuid4())
        start = time.perf_counter()
        response = await call_next(request)
        response.headers["X-Request-ID"] = request.state.request_id
        response.headers["X-Response-Time"] = str(time.perf_counter() - start)
        return response

Structured Responses

Define Pydantic models for every response shape. Use response_model to enforce serialization contracts and auto-generate OpenAPI schemas.

from pydantic import BaseModel
from typing import Generic, TypeVar

T = TypeVar("T")

class APIResponse(BaseModel, Generic[T]):
    success: bool = True
    data: T | None = None
    error: str | None = None

@router.get("/users/me", response_model=APIResponse[UserOut])
async def get_current_user(current_user: User = Depends(get_current_user)):
    return APIResponse(data=UserOut.model_validate(current_user))

Error Handling

Register exception handlers globally. Raise typed HTTP exceptions in service layers and let the handler normalize the response envelope.

from fastapi import Request
from fastapi.responses import JSONResponse

class AppException(Exception):
    def __init__(self, status: int, detail: str):
        self.status = status
        self.detail = detail

@app.exception_handler(AppException)
async def app_exception_handler(request: Request, exc: AppException):
    return JSONResponse(
        status_code=exc.status,
        content={"success": False, "error": exc.detail}
    )