Response Models and Status Codes

The response_model parameter declares what an endpoint returns. FastAPI uses it to filter the output, validate it and document it. This is also how you keep sensitive fields (like passwords) out of responses.

Filtering Output with response_model

from pydantic import BaseModel, EmailStr
from fastapi import FastAPI

class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr

class UserOut(BaseModel):
    username: str
    email: EmailStr

app = FastAPI()

@app.post("/users/", response_model=UserOut)
def create_user(user: UserIn):
    return user  # password is stored/processed but never returned

Even though the function returns the full UserIn object, the response only contains username and email. The password never leaks, and the docs show UserOut as the response schema.

Common Patterns

Disabling Default Filtering (Pydantic v2)

class Config:
    pass

@app.get("/items/", response_model=Item, response_model_exclude_unset=True)
def get_items():
    ...

Status Codes

from fastapi import FastAPI, status

@app.post("/items/", status_code=status.HTTP_201_CREATED)
def create_item(item: Item):
    return item

@app.delete("/items/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_item(item_id: int):
    return None

Returning a Custom Status with Response

from fastapi import Response, status

@app.post("/jobs/")
def create_job(response: Response):
    response.status_code = status.HTTP_202_ACCEPTED
    return {"queued": True}

Inject Response when the status code (or a header) must be decided at runtime instead of statically.

Quick Questions and Answers

Q: What happens if the returned object does not match response_model?

A: FastAPI tries to coerce/validate it; if it truly does not fit, the server raises an Internal Server Error (500) and logs the validation error. This catches bugs before bad data reaches clients.

Q: Does response_model cost performance?

A: There is a validation pass on the way out, but it is fast (Pydantic v2 is Rust-based) and buys you safety and clean docs. For very hot endpoints you can skip it, but you lose the output contract.

Q: Why not just return a dict with the right keys?

A: Dicts are untyped: one developer returning passwd instead of password ships a bug silently. response_model enforces the shape and documents it automatically.

Conclusion

response_model is your API's output contract: it filters sensitive fields, validates responses and documents them. Pair it with explicit status_code declarations so both your clients and your docs always say exactly what an endpoint does.