Examples
Representative end-to-end code for the patterns most FastAPI applications reach for first.
Third-party documentation. This is independently authored analysis of the public FastAPI codebase — not the official docs, and not reviewed or endorsed by the FastAPI team.
Examples
A few representative examples of the patterns most FastAPI applications reach for. Each is deliberately minimal — real handlers add error handling, logging, and persistence on top of the same shapes.
Examples
A minimal path operation
from fastapi import FastAPIapp = FastAPI()@app.get("/items/{item_id}")async def read_item(item_id: int, q: str | None = None):return {"item_id": item_id, "q": q}
item_id is a path parameter typed as int, so a request to /items/abc is rejected with a 422 before the function body ever runs; q is an optional query parameter.
Request body validation with Pydantic
from pydantic import BaseModelclass Item(BaseModel):name: strprice: floatis_offer: bool | None = None@app.post("/items/")async def create_item(item: Item):return item
Declaring a Pydantic model as a parameter tells FastAPI to parse and validate the JSON request body against it, and to document its exact shape in the generated OpenAPI schema.
Dependency injection with cleanup
async def get_db():db = Session()try:yield dbfinally:db.close()@app.get("/users/{user_id}")async def read_user(user_id: int, db: Session = Depends(get_db)):return db.query(User).get(user_id)
The code after yield always runs after the response is sent (or the request fails), even if the endpoint raises — FastAPI's standard pattern for any resource that needs teardown.
Background tasks
from fastapi import BackgroundTasksdef write_log(message: str):with open("log.txt", "a") as f:f.write(message + "\n")@app.post("/notify/{email}")async def notify(email: str, background_tasks: BackgroundTasks):background_tasks.add_task(write_log, f"notification sent to {email}")return {"message": "notification sent"}
Background tasks run after the response has already been sent to the client, covering lightweight fire-and-forget work without needing a separate task queue.
Edge Cases
- A request body model whose fields are all optional will still validate an empty JSON object ({}) as valid input — required-ness must be declared explicitly per field.
- Returning a raw ORM object as a response is still validated (and filtered) against response_model, so fields not declared on the model are silently dropped rather than leaked.
- A dependency's teardown code (after yield) runs regardless of whether the endpoint succeeded or raised, but it runs after the response has already been sent — it cannot change what the client received.
