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.
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.
UserIn / UserOut classes (the output often excludes secrets and includes generated fields like id).response_model=list[Item] for an endpoint returning many items.response_model=Item | None when the result may not exist.UserOutWithId(UserOut) adding fields.class Config:
pass
@app.get("/items/", response_model=Item, response_model_exclude_unset=True)
def get_items():
...
response_model_exclude_unset=True: omit fields that were not explicitly set.response_model_exclude={"secret_key"} / response_model_include={"id", "name"}: field-level control.response_model_exclude_none=True-like behavior only for None fields in some configurations; by default all fields of the model appear.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
status.HTTP_... constants for readability; they appear in the docs grouped by code.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.
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.
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.
A: Dicts are untyped: one developer returning passwd instead of password ships a bug silently. response_model enforces the shape and documents it automatically.
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.