← Back to FastAPI map
FastAPI · Foundations

Request body

Using a Pydantic model to describe the JSON sent in a request, plus single values with Body() and models inside models.

body

Overview

When a parameter is typed as a Pydantic model, FastAPI reads the request body as JSON, validates it against the model, and hands your function a typed object. Missing fields, wrong types, and constraint violations never reach your code - the client gets a 422 describing each problem. Nested models are validated as a whole tree in one pass.

Key concepts

Model as contract
The class is the schema, the validator, and the documentation of the payload - all from one definition.
Body()
Marks a plain value such as a str or int as coming from the JSON body rather than the query string.
embed=True
Expects {"item": {...}} instead of the bare object, keeping single-model endpoints consistent with multi-body ones.
Several body params
Two models in one handler are automatically expected under their parameter names: {"item": {...}, "user": {...}}.
model_dump()
Converts a model back to a dict. It is the Pydantic v2 name for v1's .dict().

Best practices

  • Keep input models separate from database models, so clients cannot set fields like id or is_admin.
  • Send bodies with POST, PUT and PATCH; GET requests should not carry a body.
  • Put validation in the model - Field constraints and validators - rather than in the handler.

Request body

Pydantic model as body

Core
from pydantic import BaseModel from typing import Optional class Item(BaseModel): name: str description: Optional[str] = None price: float tax: Optional[float] = None @app.post("/items") async def create_item(item: Item): result = item.model_dump() if item.tax: result["price_with_tax"] = item.price + item.tax return result # JSON sent by client: # { "name": "Foo", "price": 35.4, "tax": 3.2 }

Body() - singular values + embed

Body()
from fastapi import Body # Body() - single value alongside a model @app.post("/order") async def create_order( item: Item, note: str = Body(..., description="Order note") ): # Expects: { "item": {...}, "note": "..." } return {"item": item, "note": note} # embed=True - wraps model in its name in JSON @app.post("/items-wrapped") async def create_wrapped( item: Item = Body(..., embed=True) ): # Expects: { "item": {"name": "...", "price": 9.99} } return item

Nested models

Nested
from pydantic import BaseModel, HttpUrl from typing import List, Set, Dict class Image(BaseModel): url: HttpUrl # validated URL name: str class Product(BaseModel): name: str price: float tags: Set[str] = set() # unique items images: List[Image] = [] # list of nested models metadata: Dict[str, str] = {} @app.post("/products") async def create_product(product: Product): return product # FastAPI validates the entire nested structure recursively

Comments

Sign in to leave a comment. Your name and photo come from Google; nothing else is shared.

Loading comments...