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

response_model

Code explanation:

  • FastAPI filters extra fields not in ItemRead
  • OpenAPI shows exact response schema

Exclude unset/null:

python
@app.get("/items/", response_model=list[ItemRead], response_model_exclude_none=True)
def list_items():
    ...

Status Codes on Decorator

python
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 None

Common codes:

CodeConstantUse
200OKSuccessful GET/PUT
201CREATEDPOST created resource
204NO_CONTENTDELETE success
400BAD_REQUESTBusiness rule failure
401UNAUTHORIZEDMissing/invalid auth
403FORBIDDENNot allowed
404NOT_FOUNDResource missing
422UNPROCESSABLE_ENTITYValidation failed

HTTPException

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

python
raise HTTPException(
    status_code=401,
    detail="Invalid token",
    headers={"WWW-Authenticate": "Bearer"},
)

JSONResponse and Response Subclass

When you need full control:

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

python
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.