Request Body
For create and update endpoints the client sends a JSON body. In FastAPI you model the body as a Pydantic BaseModel and declare it as a parameter: FastAPI parses the JSON, validates it against the model, and hands you a fully typed object.
A Basic Body
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float = Field(gt=0)
tags: list[str] = []
@app.post("/items/")
def create_item(item: Item):
return {"created": item.name, "price": item.price}
POST /items/ with {"name": "Widget", "price": 9.99} creates an item. A missing name or a negative price returns a 422 with itemized errors.
Body with Query and Path Parameters
@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item, full: bool = False):
return {"item_id": item_id, "full_update": full, "name": item.name}
item_id comes from the path, full from the query string, and item from the JSON body - all in one signature.
Multiple Bodies with Body
By default a single Pydantic model is "the" body. For two body models, wrap them with Body:
from fastapi import Body
class A(BaseModel):
x: int
class B(BaseModel):
y: int
@app.post("/pair/")
def pair(a: A = Body(), b: B = Body()):
return {"x": a.x, "y": b.y}
The client sends {"a": {"x": 1}, "b": {"y": 2}}.
Raw JSON Access
For unstructured payloads, accept the Request and read the body yourself, or declare the parameter as dict or json.RawLike for schemaless JSON:
import json
from fastapi import Request
@app.post("/echo/")
async def echo(request: Request):
data = await request.json()
return data
Summary
Model request bodies with Pydantic BaseModels: FastAPI parses, validates, and types the JSON automatically, merges body parameters with path and query parameters in one signature, and supports multiple bodies via Body(). Reach for Request.json() only when the payload has no stable schema.