2 · Data and boundaries · 30 MIN
FastAPI request and response models
Input and output models can have different responsibilities.
Pydantic validates the request before the route function runs. Field constraints describe acceptable lengths and numeric ranges, while forbidding extra fields rejects accidental extra fields. A separate output model limits what the endpoint serializes. Do not return a database object with password hashes and assume the browser will hide unwanted fields. This preview endpoint uses no account data or persistence; adapt it to a write only after adding authenticated ownership and request-size limits at the application or proxy layer.
Inspect the generated /docs contract.
Read the example
# main.py
from fastapi import FastAPI
from pydantic import BaseModel, ConfigDict, Field
app = FastAPI()
class PlanInput(BaseModel):
model_config = ConfigDict(extra="forbid")
title: str = Field(min_length=3, max_length=80)
weekly_goal: int = Field(ge=1, le=20, strict=True)
class PlanPreview(BaseModel):
title: str
weekly_goal: int
@app.post("/preview", response_model=PlanPreview)
def preview(plan: PlanInput):
return PlanPreview(title=plan.title, weekly_goal=plan.weekly_goal)Check the expected output
A valid body produces the preview; a numeric string goal, extra field or out-of-range goal produces validation status 422.
Your challenge
Add trimmed-title validation that rejects whitespace-only values, then test input coercion and response field filtering.
Solution cost: O(f + m) validation and serialization. time · O(f + m) request and response model data. space
Common trap
CORS settings do not authenticate a caller or authorize a record.
Study the project implementation
# main.py
from fastapi import FastAPI
from pydantic import BaseModel, ConfigDict, Field
app = FastAPI()
class PlanInput(BaseModel):
model_config = ConfigDict(extra="forbid")
title: str = Field(min_length=3, max_length=80)
weekly_goal: int = Field(ge=1, le=20, strict=True)
class PlanPreview(BaseModel):
title: str
weekly_goal: int
@app.post("/preview", response_model=PlanPreview)
def preview(plan: PlanInput):
return PlanPreview(title=plan.title, weekly_goal=plan.weekly_goal)Further reading: Official documentation
Next lesson: FastAPI dependencies and cleanup →