How do you accept JSON request bodies using Pydantic models?
FastAPI automatically parses JSON request bodies into Pydantic models when you declare a parameter with a Pydantic model type. The framework inspects the function signature, sees the Pydantic type, and reads the request body as JSON, validates it against the model, and passes the validated object to your handler.
How it works:
- Client sends a POST/PUT/PATCH request with a JSON body
- FastAPI reads the raw body and parses it as JSON
- The JSON dict is passed to the Pydantic model constructor
- Pydantic validates all fields (types, constraints, custom validators)
- If validation fails, FastAPI returns a 422 Unprocessable Entity with detailed error messages
- If validation passes, your function receives a typed Python object
Key features:
- Automatic type coercion: strings that look like numbers are coerced where safe
- Default values: fields with defaults become optional in the request
- Nested models: Pydantic models can contain other Pydantic models
- JSON Schema: the model auto-generates the request body schema in Swagger docs
Validation errors:
When validation fails, FastAPI returns a structured 422 response with detail containing an array of error objects, each specifying the field location, message, and error type.
# Declare a Pydantic model
class ItemCreate(BaseModel):
name: string (required)
price: float (must be > 0)
tags: list of strings (defaults to empty)
# Use it as a parameter type
@app.POST("/items/")
function create_item(item: ItemCreate):
# item is already validated
# Access fields: item.name, item.price, item.tags
return item as dict
from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel, Field
app = FastAPI()
class ItemCreate(BaseModel):
name: str = Field(min_length=1, max_length=100)
price: float = Field(gt=0)
description: str | None = None
tags: list[str] = []
@app.post("/items/", status_code=201)
def create_item(item: ItemCreate):
"""item is auto-parsed from the JSON request body."""
return {"item": item.model_dump(), "message": "created"}
client = TestClient(app)
# Valid JSON body
response = client.post("/items/", json={
"name": "Widget",
"price": 9.99,
"tags": ["sale"]
})
print("Valid:", response.status_code, response.json())
# Missing required field
response = client.post("/items/", json={"price": 9.99})
print("Missing name:", response.status_code)
# Invalid type
response = client.post("/items/", json={"name": "Widget", "price": "free"})
print("Bad type:", response.status_code)
- •Declare a Pydantic model as a function parameter and FastAPI auto-parses the JSON body into it
- •Validation failures return 422 with detailed error messages listing every invalid field
- •Fields with default values are optional in the request body
- •The Pydantic model auto-generates the request body schema in Swagger UI docs
- •A parameter typed as a Pydantic model is always read from the request body, not from query or path
- •FastAPI attempts to parse the body as JSON regardless of Content-Type for Pydantic model parameters -- a missing or non-parseable body causes a 422 validation error
- •Pydantic v2 is stricter by default -- 'true' (string) won't coerce to True (bool) unless you configure it