Request & Response Models
FastAPI uses Pydantic 2 models to validate requests and shape responses at the HTTP boundary.
Recipe
Quick-reference recipe card - copy-paste ready.
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class ItemCreate(BaseModel):
name: str = Field(min_length=1)
price: float = Field(gt=0)
class ItemRead(BaseModel):
id: int
name: str
price: float
@app.post('/items', response_model=ItemRead, status_code=201)
def create_item(payload: ItemCreate) -> ItemRead:
return ItemRead(id=1, **payload.model_dump())When to reach for this:
- JSON bodies need field rules
- Responses must hide secrets
- OpenAPI should match runtime
Working Example
from datetime import datetime
from fastapi import FastAPI, Query
from pydantic import BaseModel, ConfigDict, Field, field_validator
app = FastAPI()
class Page(BaseModel):
page: int = Field(1, ge=1)
size: int = Field(20, ge=1, le=100)
class ArticleIn(BaseModel):
title: str
tags: list[str] = Field(default_factory=list)
@field_validator('tags')
@classmethod
def norm(cls, v):
return sorted({t.strip().lower() for t in v})
class ArticleOut(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: int
title: str
tags: list[str]
created_at: datetime
@app.get('/articles', response_model=list[ArticleOut])
def list_articles(p: Page = Query()) -> list[ArticleOut]:
return [ArticleOut(id=1, title='Demo', tags=['api'], created_at=datetime.now())]What this demonstrates:
- Separate In/Out models
- field_validator normalization
- from_attributes for ORM
Deep Dive
How It Works
- FastAPI parses JSON into Pydantic models before your function runs.
response_modelfilters output fields for clients and OpenAPI.- Use
model_dump(mode='json')for explicit serialization.
Python Notes
# Reject unknown keys at the boundary
class StrictIn(BaseModel):
model_config = ConfigDict(extra='forbid')Gotchas
- Boundary validation skipped - Invalid data propagates to the database.. Fix: Validate with Pydantic at routes and web forms..
- Leaking internal exceptions - Stack traces reach clients.. Fix: Register exception handlers and return safe messages..
- Blocking the event loop - Async routes call sync I/O.. Fix: Use async drivers or run_in_threadpool for blocking code..
- God modules - All logic in one file.. Fix: Split routers, services, and repositories by domain..
- Missing timeouts - Hung upstream calls stall workers.. Fix: Set timeouts on HTTP and database clients..
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Framework X native pattern | You are already standardized on that stack | You need OpenAPI-first async APIs |
| Serverless functions | Low traffic bursty workloads | Long-lived connections or WebSockets |
| GraphQL | Clients need flexible field selection | Simple CRUD with strong caching |
FAQs
When should I use request and response models?
Reach for it when the patterns on this page match your integration or design constraint.
What is the most common mistake with request and response models?
Skipping validation or error handling at the boundary and pushing complexity into handlers.
How do I test request and response models?
Use framework test clients with dependency overrides and assert status codes and JSON bodies.
Does request and response models work with async code?
Yes when you use async-compatible drivers and avoid blocking calls in async routes.
How does request and response models interact with Pydantic 2?
Models validate at the edge; services should trust typed objects inside.
What belongs in a service layer vs routes?
Routes parse and authorize; services implement business rules and persistence.
How do I handle errors consistently?
Map domain errors to HTTP exceptions or a shared error schema.
Should I pin dependency versions?
Yes - lock FastAPI, Django, Flask, and drivers in production images.
How do I document this for clients?
Export OpenAPI and keep response models aligned with real payloads.
Where do I learn more in this cookbook?
Follow the Related links at the bottom of this page.
Related
- Dependency Injection - Share pagination deps
- FastAPI Basics - First routes
- Testing FastAPI - 422 assertions
- Authentication & Authorization - Security models
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.