Response Models and Status Codes
Introduction
Response models document and filter what clients receive. Status codes express outcomes—201 for creation, 404 for missing resources. FastAPI enforces response_model at runtime and in OpenAPI, keeping APIs consistent and safe.
Prerequisites
- Pydantic Models and Validation
- Basic HTTP status code meanings
response_model
Code explanation:
- FastAPI filters extra fields not in
ItemRead - OpenAPI shows exact response schema
Exclude unset/null:
@app.get("/items/", response_model=list[ItemRead], response_model_exclude_none=True)
def list_items():
...Status Codes on Decorator
from fastapi import status
@app.post("/items", response_model=ItemRead, status_code=status.HTTP_201_CREATED)
def create_item(item: ItemCreate):
return ItemRead(id=1, name=item.name, price=item.price)
@app.delete("/items/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_item(item_id: int):
return NoneCommon codes:
| Code | Constant | Use |
|---|---|---|
| 200 | OK | Successful GET/PUT |
| 201 | CREATED | POST created resource |
| 204 | NO_CONTENT | DELETE success |
| 400 | BAD_REQUEST | Business rule failure |
| 401 | UNAUTHORIZED | Missing/invalid auth |
| 403 | FORBIDDEN | Not allowed |
| 404 | NOT_FOUND | Resource missing |
| 422 | UNPROCESSABLE_ENTITY | Validation failed |
HTTPException
from fastapi import HTTPException
@app.get("/items/{item_id}")
def get_item(item_id: int):
if item_id < 1:
raise HTTPException(status_code=404, detail="Item not found")
return {"item_id": item_id}Custom headers:
raise HTTPException(
status_code=401,
detail="Invalid token",
headers={"WWW-Authenticate": "Bearer"},
)JSONResponse and Response Subclass
When you need full control:
from fastapi.responses import JSONResponse
@app.get("/legacy")
def legacy():
return JSONResponse(
status_code=200,
content={"status": "ok"},
)Prefer response_model when shape is stable—better OpenAPI integration.
Unified API Envelope (Team Pattern)
Document whether code != 0 uses HTTP 200 or 4xx—pick one style per project.
Tip
Do Not Mix Envelope and Raw HTTP Semantics Blindly
Clients should know if 404 or 200 + code=404 means not found.
Multiple Response Types (OpenAPI)
from fastapi.responses import JSONResponse
@app.get(
"/items/{item_id}",
response_model=ItemRead,
responses={404: {"description": "Not found"}},
)
def get_item(item_id: int):
...Advanced: Union response models for polymorphic endpoints.
Compare With Flask
Flask returns jsonify, tuples, or dicts manually—see Flask responses. FastAPI ties status, model, and docs in the decorator.
FAQ
response_model strips password field?
Yes—if you return a dict with extra keys, they are removed unless response_model_exclude_unset etc. says otherwise.
Return ORM object directly?
Use response_model=ItemRead with from_attributes=True on schema.
204 with body?
Avoid—HTTP spec prefers empty body; some clients ignore body on 204.
Raise vs return error JSON?
Use HTTPException for standard errors; custom handler for envelope—error handling chapter.
List response pagination wrapper?
response_model=Paginated[ItemRead] custom generic—common in project chapters.
Change status in function?
Prefer decorator status_code; or return Response with status_code set.