Secure FastAPI Responses: Separate Input and Output Models with response_model
This article shows how FastAPI's response_model lets you define distinct input and output Pydantic models to hide sensitive fields like passwords, outlines common CRUD scenarios, demonstrates partial updates with PATCH and exclude_unset, and explains why extracting models into a dedicated file improves code organization.
1. Input and Output Models Are Different
When a client registers a user it sends a JSON payload containing email, password, and full_name. The API must not return the password hash. FastAPI handles this by specifying a response_model that defines the shape of the response data.
{
"email": "[email protected]",
"password": "secret123",
"full_name": "Alice"
}The endpoint returns only the fields defined in the output model:
{
"email": "[email protected]",
"full_name": "Alice"
}Two Pydantic models are defined:
class UserCreate(BaseModel):
email: EmailStr
password: str = Field(..., min_length=8)
full_name: str | None = None
class UserPublic(BaseModel):
email: EmailStr
full_name: str | NoneThe route uses
@app.post("/users", response_model=UserPublic, status_code=201). Regardless of what the function returns, FastAPI serializes the result according to UserPublic, so the password field never appears in the response.
2. Model Separation Strategies for Three Common Scenarios
User registration : input model UserCreate, output model UserPublic – password is received but never returned.
Item CRUD : input model ItemCreate (fields name and price), output model ItemResponse (adds id and created_at).
Order creation : input model OrderCreate, output model Order – output includes the automatically calculated total_price.
Example for the item scenario:
class ItemCreate(BaseModel):
name: str = Field(..., min_length=1)
price: float = Field(..., gt=0)
class ItemResponse(BaseModel):
id: int
name: str
price: float
created_at: float
@app.post("/items", response_model=ItemResponse, status_code=201)
def create_item(item: ItemCreate):
new_item = save_to_db(item)
return ItemResponse(**new_item)3. Partial Updates with PATCH and exclude_unset
In REST, PUT replaces the whole resource while PATCH updates only the provided fields. FastAPI can handle partial updates by defining an update model and calling model_dump(exclude_unset=True) to keep only the fields the client sent.
class ItemUpdate(BaseModel):
name: str | None = None
price: float | None = None
@app.patch("/items/{item_id}", response_model=ItemResponse)
def update_item(item_id: int, item_update: ItemUpdate):
for item in ITEMS_DB:
if item["id"] == item_id:
item.update(item_update.model_dump(exclude_unset=True))
return ItemResponse(**item)The exclude_unset=True flag means only the fields actually supplied by the client are applied, avoiding manual checks such as if "price" in data.
4. Extracting Models to a Separate File
On Day 4 the tutorial moves all Pydantic models into a dedicated models.py file, leaving route logic in main.py:
fastapi-14days/
├── main.py # routes
├── models.py # all data models
└── tests/Benefits of this organization:
Models are immediately visible and not hidden among route code.
The same model can be reused across multiple endpoints.
Tests can import models directly without pulling in routing logic.
5. What Was Done on Day 4
Extracted all Pydantic models into models.py for unified management.
Defined UserCreate, UserPublic, ItemCreate, ItemUpdate, and ItemResponse models.
Used response_model to control the response structure, ensuring passwords never leak.
Implemented a PATCH /items/{id} endpoint for partial updates.
Added seven new test cases, bringing the total to 29 passing tests.
6. Next Steps
Day 5 will cover FastAPI's dependency injection system, showing how to extract reusable logic into independent functions and invoke them from any route.
7. Related Links
Official FastAPI documentation (Chinese):
https://fastapi.tiangolo.com/zh/tutorial/response-model/
https://fastapi.tiangolo.com/zh/tutorial/extra-models/Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Tech Ocean
Focused on AI programming, sharing ready-to-use development efficiency solutions.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
