Choosing Between Pydantic Models and Plain Dict Request Bodies in FastAPI
Guide comparing Pydantic models vs. plain dict request bodies in FastAPI, with a decision table, trade‑offs, and a working example.
22 Oct 2025, 01:08 UTC

Decision and Constraints
The decision is whether to define a Pydantic model for request bodies or to accept a plain dict in a FastAPI endpoint. Constraints include:
- FastAPI version must match the Pydantic version (v1 or v2) to avoid breaking changes.
- If using a plain dict, you must implement validation and sanitisation yourself.
- Pydantic models add a small instantiation cost but provide automatic OpenAPI schema generation.
Comparison Table
| Option | Validation | Automatic Docs | Flexibility | Performance |
|---|---|---|---|---|
| Pydantic Model | Full (type checks, constraints, custom validators) | Yes – schema generated from model fields | Limited to declared fields (extra fields ignored or rejected based on config) | Negligible overhead (model instantiation) |
| Plain dict | None – manual validation required | No – you must describe the schema manually in docstrings or external tools | High – any JSON structure is accepted | Slightly faster (no model creation) |
Trade‑offs
Using a Pydantic model guarantees that incoming data conforms to the declared types and any additional constraints (e.g., gt=0, regex patterns). FastAPI returns a detailed 422 Unprocessable Entity response with error locations, which improves developer experience and reduces bugs. The downside is the need to define a model class and keep it in sync with the Pydantic version used by FastAPI.
A plain dict offers maximal flexibility – you can accept arbitrary JSON shapes without changing code. However, you lose automatic validation, automatic OpenAPI documentation, and you must write custom validation logic to guard against missing fields, wrong types, or unexpected keys that could lead to injection or data corruption.
Implementation Example
Define a Pydantic model for an item and use it in a POST endpoint:
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
name: str = Field(..., min_length=1)
price: float = Field(..., gt=0)
@app.post("/items/")
async def create_item(item: Item):
return item
FastAPI will automatically:
- Parse the request body as JSON.
- Instantiate an
Itemmodel, validating types and constraints. - Return a
200response with the serialized model on success. - Return a
422response with a JSON error detail on failure.
Verification Steps
You can confirm the behaviour locally:
- Start the server:
uvicorn main:app --reload(run in the directory containing the code). - Send a valid payload:
curl -X POST "http://localhost:8000/items/" \
-H "Content-Type: application/json" \
-d '{"name":"Widget","price":12.5}'
Expect a 200 response containing the same JSON.
- Send an invalid payload (missing price):
curl -X POST "http://localhost:8000/items/" \
-H "Content-Type: application/json" \
-d '{"name":"Widget"}'
Expect a 422 response with a body similar to:
{
"detail": [
{
"loc": ["body", "price"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
- Open the automatic docs:
http://localhost:8000/docsand verify that the POST /items/ endpoint shows a request body schema withname(string) andprice(number) fields.
Limitations and Practical Checks
While Pydantic models cover most validation needs, extremely complex validation (e.g., cross‑field dependencies that cannot be expressed with built‑in validators) may require custom validators or a post‑processing step. In such cases, you can still keep the model for basic structure and add a @model_validator(mode='after') method.
To check that the model is being used, you can add a temporary print(item) inside the endpoint and observe the output in the server logs when a request is made.
Choosing a Pydantic model is generally recommended for most APIs because it provides safety, documentation, and consistent error handling with minimal performance impact. Reserve plain dict bodies for truly dynamic endpoints where the schema cannot be known ahead of time, and ensure you implement rigorous validation and sanitisation in that case.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.