FastAPI Day 3: Automating Data Validation with Pydantic Models (No Hand‑Written if‑else)
This article shows how FastAPI combined with Pydantic lets you define schema‑driven validation—including nested models, Field metadata, and separate input/output models—so you can drop manual if‑else checks and rely on automatic 422 responses and generated OpenAPI docs.
1. Pydantic models as data schema
Define a product schema using a Pydantic BaseModel with fields name, price, description, and tags. Validation rules such as min_length, max_length, and gt=0 are declared in the model, so the endpoint code does not need explicit checks.
from pydantic import BaseModel, Field
class ProductCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=100)
price: float = Field(..., gt=0)
description: str | None = None
tags: list[str] = Field(default_factory=list)In a FastAPI route the parameter product: ProductCreate is already validated and can be returned directly.
@app.post("/products")
def create_product(product: ProductCreate):
# product is clean data after validation
return {"id": 1, **product.model_dump()}FastAPI automatically validates each field, applies the Field constraints, and returns a 422 response if validation fails, preventing the business logic from executing.
2. Nested models
When a product includes images, a separate Image model can be nested inside ProductCreate.
class Image(BaseModel):
url: str
alt: str | None = None
class ProductCreate(BaseModel):
name: str
price: float
images: list[Image] = Field(default_factory=list)Sending a JSON with a list of image objects triggers automatic parsing and validation, including URL format checks.
{
"name": "Monitor",
"price": 2999.0,
"images": [
{"url": "https://example.com/1.jpg", "alt": "Front"},
{"url": "https://example.com/2.jpg", "alt": "Side"}
]
}3. Field validation capabilities
The Field function not only defines defaults but also adds metadata such as description, which appears in the generated OpenAPI docs ( /docs).
class ProductCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=100,
description="Product name")
price: float = Field(..., gt=0,
description="Product price (CNY)")4. Separating input and output models
Separate models for creation and response prevent internal fields from leaking.
class ProductCreate(BaseModel):
name: str
price: float
class Product(BaseModel):
id: int # only in responses
name: str
price: floatDeclare the response type with -> Product in the route signature.
5. What was done on Day 3
Defined five Pydantic models: ProductCreate, Product, Image, OrderCreate, Order.
Implemented POST /products supporting nested image lists.
Implemented POST /orders with a required non‑empty product list.
All seven test cases passed, correctly catching missing fields, negative prices, and empty lists.
6. Next steps
Day 4 will cover response models ( response_model) and best practices for separating input and output schemas.
Related links
Official FastAPI documentation (Chinese):
https://fastapi.tiangolo.com/zh/tutorial/body/
https://fastapi.tiangolo.com/zh/tutorial/body-nested-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.
