Python FastAPI Cheat Sheet
Covers FastAPI route definitions, path and query parameters, Pydantic request/response models, and the dependency injection system.
Minimal FastAPI App
Auto-generated docs come for free.
from fastapi import FastAPIapp = FastAPI()@app.get("/")def read_root(): return {"message": "Hello, FastAPI!"}# Run with: uvicorn main:app --reload# Interactive docs auto-generated at /docs (Swagger UI) and /redoc
Path & Query Parameters
Parameters are validated automatically from type hints.
from typing import Optional@app.get("/items/{item_id}")def read_item(item_id: int, q: Optional[str] = None): # item_id is validated as int from the URL path # q is an optional query string param: /items/5?q=foo return {"item_id": item_id, "q": q}@app.get("/items/")def list_items(skip: int = 0, limit: int = 10): return {"skip": skip, "limit": limit}
Request Bodies with Pydantic
Define and validate JSON payloads.
from pydantic import BaseModelclass Item(BaseModel): name: str price: float is_offer: bool = False@app.post("/items/")def create_item(item: Item): # FastAPI parses & validates the JSON body against Item return {"name": item.name, "total": item.price}@app.put("/items/{item_id}")def update_item(item_id: int, item: Item) -> Item: return item
Dependency Injection
Share reusable logic like auth checks and pagination across routes.
from fastapi import Depends, HTTPExceptiondef get_token_header(x_token: str): if x_token != "secret": raise HTTPException(status_code=400, detail="Invalid token") return x_token@app.get("/secure-data/")def secure_data(token: str = Depends(get_token_header)): return {"token": token}# Class-based dependency with shared stateclass Pagination: def __init__(self, skip: int = 0, limit: int = 10): self.skip = skip self.limit = limit@app.get("/users/")def list_users(pagination: Pagination = Depends()): return {"skip": pagination.skip, "limit": pagination.limit}
FastAPI Essentials
Frequently used decorators and parameters.
- @app.get/post/put/delete- Decorators mapping a function to an HTTP method and path
- response_model=- Declares the Pydantic model used to serialize and validate the response
- status_code=201- Sets the default HTTP status code for a route
- async def- Route handlers can be async for non-blocking I/O; sync def also works
- HTTPException- Raise to short-circuit with an HTTP error status and detail message
- APIRouter- Group related routes into a module, then include_router() them into the app
- BackgroundTasks- Run a function after the response is returned (e.g. sending an email)
Async Database Sessions
Yield a scoped async session per request using SQLAlchemy's async engine.
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSessionfrom fastapi import Dependsengine = create_async_engine("postgresql+asyncpg://user:pw@host/db", pool_size=10)SessionLocal = async_sessionmaker(engine, expire_on_commit=False)async def get_db() -> AsyncSession: async with SessionLocal() as session: yield session # Session closes automatically on generator exit, even on exception@app.get("/users/{user_id}")async def get_user(user_id: int, db: AsyncSession = Depends(get_db)): result = await db.get(User, user_id) return result
Custom Middleware & CORS
Wrap every request/response and configure cross-origin access.
import timefrom starlette.middleware.base import BaseHTTPMiddlewarefrom fastapi.middleware.cors import CORSMiddlewareclass TimingMiddleware(BaseHTTPMiddleware): async def dispatch(self, request, call_next): start = time.perf_counter() response = await call_next(request) response.headers["X-Process-Time"] = str(time.perf_counter() - start) return responseapp.add_middleware(TimingMiddleware)app.add_middleware( CORSMiddleware, allow_origins=["https://example.com"], allow_methods=["GET", "POST"], allow_headers=["*"], allow_credentials=True,)
Lifespan Events
Manage startup/shutdown resources with an async context manager instead of the deprecated event decorators.
from contextlib import asynccontextmanagerfrom fastapi import FastAPI@asynccontextmanagerasync def lifespan(app: FastAPI): # Startup: runs once before the app accepts requests app.state.redis = await create_redis_pool() yield # Shutdown: runs once after the app stops accepting requests await app.state.redis.close()app = FastAPI(lifespan=lifespan)@app.get("/cache/{key}")async def read_cache(key: str): return await app.state.redis.get(key)
Custom Exception Handlers & Testing
Translate domain exceptions into consistent JSON errors and verify routes with TestClient.
from fastapi import Requestfrom fastapi.responses import JSONResponseclass OutOfStockError(Exception): def __init__(self, sku: str): self.sku = sku@app.exception_handler(OutOfStockError)async def out_of_stock_handler(request: Request, exc: OutOfStockError): return JSONResponse(status_code=409, content={"error": f"{exc.sku} is out of stock"})# Testing (pytest + httpx-based TestClient)from fastapi.testclient import TestClientclient = TestClient(app)def test_read_item(): response = client.get("/items/5?q=foo") assert response.status_code == 200 assert response.json()["item_id"] == 5
Advanced Reference
Lesser-known but frequently needed FastAPI/Starlette building blocks.
- WebSocket- @app.websocket("/ws") accepts a persistent connection; use await websocket.accept()/receive_text()/send_text()
- OAuth2PasswordBearer- Standard security scheme for extracting and validating a bearer token from the Authorization header
- StreamingResponse- Streams a generator/iterator body to the client without buffering the whole payload in memory
- Depends(..., use_cache=True)- Dependencies are cached per-request by default; set use_cache=False to force re-evaluation
- model_config = ConfigDict(...)- Pydantic v2 way to configure a model (e.g. from_attributes=True for ORM objects)
- field_validator- Pydantic v2 decorator for custom per-field validation logic, replacing the old @validator
- app.mount()- Mounts a sub-application or StaticFiles instance at a path prefix
- Response(headers=...)- Inject a raw Response parameter into a handler to set headers/cookies without changing the return type
FastAPI generates the OpenAPI schema directly from your type hints and Pydantic models, so keep response_model set on every route — it also filters the response down to only the fields you intended to expose.