JSON in FastAPI — Pydantic Models, Request Bodies, and Response Serialization
FastAPI uses Pydantic models as the bridge between JSON and Python. When you declare a Pydantic model as a parameter, FastAPI automatically parses the JSON request body, validates it, and provides it as a typed Python object — with no boilerplate.
Defining Pydantic models for JSON request bodies
Declare a class that inherits from BaseModel. FastAPI reads the request body as JSON and validates it against the model automatically.
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
from typing import Optional
app = FastAPI()
class CreateUserRequest(BaseModel):
name: str
email: EmailStr
age: Optional[int] = None
@app.post("/users")
async def create_user(user: CreateUserRequest):
# user is fully typed and validated
print(user.name, user.email)
return {"id": 1, "name": user.name}Returning JSON responses
Return any Pydantic model, dict, list, or primitive from a route function. FastAPI serialises it to JSON automatically using the response_model for filtering.
from pydantic import BaseModel
class UserResponse(BaseModel):
id: int
name: str
email: str
@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
# response_model filters and validates the output shape
return {"id": user_id, "name": "Alice", "email": "alice@example.com"}
# Return a list
@app.get("/users", response_model=list[UserResponse])
async def list_users():
return [{"id": 1, "name": "Alice", "email": "alice@example.com"}]Nested models and optional fields
Compose complex JSON shapes by nesting Pydantic models. Use Optional[T] (or T | None in Python 3.10+) for fields that may be absent.
from pydantic import BaseModel
from typing import Optional
class Address(BaseModel):
street: str
city: str
country: str = "US" # default value
class User(BaseModel):
id: int
name: str
address: Optional[Address] = None # nested, optional
@app.post("/users")
async def create_user(user: User):
if user.address:
print(user.address.city)
return userCustom JSON serializers
Override JSON serialisation for types that Pydantic doesn't handle by default using model_config and custom validators (Pydantic v2).
from pydantic import BaseModel
from decimal import Decimal
class Product(BaseModel):
name: str
price: Decimal
model_config = {
"json_encoders": {
Decimal: lambda v: float(v),
}
}
product = Product(name="Widget", price=Decimal("9.99"))
print(product.model_dump_json())
# {"name":"Widget","price":9.99}Handling datetime and UUID fields
Pydantic natively supports datetime and UUID types. FastAPI serialises datetime to ISO 8601 strings and UUID to hyphenated strings in JSON responses.
from fastapi import FastAPI
from pydantic import BaseModel
from datetime import datetime
from uuid import UUID, uuid4
app = FastAPI()
class Event(BaseModel):
id: UUID
name: str
created_at: datetime
@app.get("/events/{event_id}")
async def get_event(event_id: UUID) -> Event:
return Event(
id=event_id,
name="Launch",
created_at=datetime(2026, 1, 15, 10, 30, 0),
)
# Response: {"id":"...", "name":"Launch", "created_at":"2026-01-15T10:30:00"}Related Tools
Frequently Asked Questions
How does FastAPI parse JSON request bodies?▾
Declare a Pydantic BaseModel subclass as a route parameter. FastAPI reads the Content-Type: application/json request body, parses it, and validates it against the model. If validation fails, it returns a 422 Unprocessable Entity response automatically.
How do I return a JSON response from a FastAPI route?▾
Return a Pydantic model instance, a dict, a list, or a primitive value from your route function. FastAPI serialises it to JSON. Use response_model= to declare the expected output shape and filter extra fields.
How do I handle optional JSON fields in FastAPI?▾
Declare the field as Optional[T] = None (or T | None = None in Python 3.10+). FastAPI and Pydantic treat the field as optional — it will be None if absent from the request body.
How do I serialise datetime objects to JSON in FastAPI?▾
Use datetime fields directly in your Pydantic model. FastAPI serialises them to ISO 8601 strings (e.g. '2026-01-15T10:30:00') automatically. No custom encoder is needed for standard datetime objects.
What is response_model in FastAPI?▾
response_model= on a route decorator tells FastAPI what shape the response should have. It filters out fields not in the model (useful for hiding internal fields like passwords) and validates the output. Set response_model_exclude_unset=True to omit unset optional fields.
JSON in Other Languages
Format and validate your JSON instantly
Free, no ads, no sign-up. Also converts JSON to TypeScript, YAML, CSV, and more.
Open JSON Formatter →If jsondecode.com saved you time, share it with your team
Free forever. No ads. No sign-up. Help other developers find it.