YouTip LogoYouTip

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`
← Fastapi Status Code 2Fastapi Path Params Validation β†’