FastAPI Response Model
Response models are used to declare the data structure returned by the API. By declaring a response model, FastAPI automatically handles validation, serialization, and filtering of output data, ensuring that the client only receives the expected data.
Using return type annotations
The simplest way is to directly annotate the return type of the path operation function:
Example
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
@app.get("/items/{item_id}", response_model=Item)
async def read_item(item_id: int):
# The returned data will be automatically filtered and validated according to the Item model
return {
"name": "Foo",
"description": "A very nice Item",
"price": 22.2,
"secret": "this should not be visible", # Fields not in Item will be filtered
}
FastAPI uses the response model to accomplish the following:
| Features | Description |
|---|---|
| Data verification | If the returned data does not match the model, it indicates a problem with the application code. |
| Data filtering | Only return the fields defined in the model, filtering out extra fields (this is important for security). |
| Generate documentation | Display the response structure in the OpenAPI documentation. |
| serialization | Use Pydantic (Rust implementation) to efficiently convert data to JSON. |
response_model parameter
When the return type is inconsistent with the response model, use the decorator'sresponse_modelParameters:
Example
from pydantic import BaseModel, EmailStr
app = FastAPI()
# Input model (contains password)
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
# Output model (without password)
class UserOut(BaseModel):
username: str
email: EmailStr
# Function receives UserIn, but response uses UserOut
@app.post("/users/", response_model=UserOut)
async def create_user(user: UserIn):
# The returned user contains the password, but response_model=UserOut will filter out the password.
return user
This is an important way to protect sensitive data. By using different input and output models, sensitive fields such as passwords never appear in API responses.
Return type and data filtering
RecommendedClassInheritancecomeImplementationInput/OutputModelofDivide离,这sample既abilityLetEditorand mypy Correct understandingType,又abilityLet FastAPI FilterData:
Example
from pydantic import BaseModel, EmailStr
app = FastAPI()
# Basic User Model
class BaseUser(BaseModel):
username: str
email: EmailStr
# Input model: inherits base model, adds password field
class UserIn(BaseUser):
password: str
@app.post("/users/")
async def create_user(user: UserIn) -> BaseUser:
# The return type annotation is BaseUser, and FastAPI will filter out the password field.
# The editor and mypy are also satisfied, because UserIn is a subclass of BaseUser
return user
Excluding unset default values
Usageresponse_model_exclude_unset=True, only return fields that actually have values set:
Example
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float = 10.5
tags: list[str] = []
items = {
"foo": {"name": "Foo", "price": 50.2},
"bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
"baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}
@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
return items[item_id]
Comparison of responses for different item_id:
| item_id | response | Description |
|---|---|---|
foo | {"name": "Foo", "price": 50.2} | Only explicitly set fields are returned, omitting default values. |
bar | {"name": "Bar", "description": "...", "price": 62, "tax": 20.2} | All fields have actual values, so all are returned |
Related filter parameters:
| Parameter | Description |
|---|---|
response_model_exclude_unset | Exclude fields with unset values |
response_model_exclude_defaults | Exclude fields with default values |
response_model_exclude_none | Exclude fields with value None |
Include/exclude specific fields
Usageresponse_model_includeandresponse_model_excludePrecisely control output fields:
Example
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float = 10.5
# Only contains name and description
@app.get("/items/{item_id}", response_model=Item, response_model_include={"name", "description"})
async def read_item_name(item_id: str):
return items[item_id]
# Exclude Tax
@app.get("/items/{item_id}/no-tax", response_model=Item, response_model_exclude={"tax"})
async def read_item_no_tax(item_id: str):
return items[item_id]
Although
response_model_includeandresponse_model_excludeCan quickly filter fields, but it is recommended to use multiple model classes instead, because they cannot remove the excluded fields from the OpenAPI documentation.
Summary
- Usage
response_modelParameter or return type annotations declare the response model. - The core role of the response model is data filtering, protecting sensitive data from being leaked.
- Use different models for input and output to ensure that fields such as passwords do not appear in the response.
response_model_exclude_unsetOnly return fields that are actually set- It is recommended to use model inheritance + return type annotations rather than
response_model_include/exclude