Fastapi Response Model
Response models are used to declare the data structure returned by an API. By declaring a response model, FastAPI automatically completes output data validation, serialization, and filtering, 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 fastapi import FastAPI
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 out
}
FastAPI uses the response model to accomplish the following:
| Feature | Description |
| --- | --- |
| Data Validation | If the returned data does not match the model, it indicates a problem with the application code |
| Data Filtering | Only returns the fields defined in the model, filtering out extra fields (this is important for security) |
| Documentation Generation | Displays the response structure in the OpenAPI documentation |
| Serialization | Uses Pydantic (Rust implementation) to efficiently convert data to JSON |
* * *
## The response_model Parameter
When the return type differs from the response model, use the decorator's `response_model` parameter:
## Example
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
# Input model (includes password)
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
# Output model (does not include password)
class UserOut(BaseModel):
username: str
email: EmailStr
# The function receives UserIn, but the 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 it out
return user
> This is an important method for protecting sensitive data. By using different input and output models, you ensure that sensitive fields like passwords never appear in API responses.
* * *
## Return Types and Data Filtering
It is recommended to use class inheritance to separate input/output models. This allows editors and mypy to correctly understand the types while letting FastAPI filter the data:
## Example
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
# Base user model
class BaseUser(BaseModel):
username: str
email: EmailStr
# Input model: inherits the base model, adds the password field
class UserIn(BaseUser):
password: str
@app.post("/users/")
async def create_user(user: UserIn) -> BaseUser:
# The return type is annotated as BaseUser, FastAPI will filter out the password field
# Editors and mypy are also satisfied because UserIn is a subclass of BaseUser
return user
* * *
## Exclude Unset Default Values
Use `response_model_exclude_unset=True` to only return fields that have actually been set with values:
## Example
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None=None
price: float
tax: float=10.5
tags: list=[]
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
Comparison of responses for different item_ids:
| item_id | Response | Description |
| --- | --- | --- |
| `foo` | `{"name": "Foo", "price": 50.2}` | Only returns explicitly set fields, omitting default values |
| `bar` | `{"name": "Bar", "description": "...", "price": 62, "tax": 20.2}` | All fields have actual values, all are returned |
Related filtering parameters:
| Parameter | Description |
| --- | --- |
| `response_model_exclude_unset` | Exclude fields whose values have not been set |
| `response_model_exclude_defaults` | Exclude fields whose values are the default |
| `response_model_exclude_none` | Exclude fields whose values are None |
* * *
## Include/Exclude Specific Fields
Use `response_model_include` and `response_model_exclude` to precisely control output fields:
## Example
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None=None
price: float
tax: float=10.5
# Only include 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
# 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
> Although `response_model_include` and `response_model_exclude` can quickly filter fields, it is recommended to use multiple model classes instead, as they cannot remove excluded fields from the OpenAPI documentation.
* * *
## Summary
* Use the `response_model` parameter or return type annotations to declare response models
* The core role of a response model is data filtering, protecting sensitive data from being exposed
* Use different models for input and output to ensure fields like passwords do not appear in responses
* `response_model_exclude_unset` only returns fields that were actually set
* It is recommended to use model inheritance + return type annotations instead of `response_model_include/exclude`
YouTip