File size: 4,586 Bytes
a152b95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# Request Body in FastAPI

A request body is data sent by the client to your API, typically as JSON in POST, PUT, or PATCH requests. FastAPI uses Pydantic models to declare, validate, and serialize request bodies with full type safety.

## Defining a Request Body with Pydantic

```python
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float = 0.0

@app.post("/items/")
async def create_item(item: Item):
    item_dict = item.model_dump()
    if item.tax > 0:
        price_with_tax = item.price + item.tax
        item_dict.update({"price_with_tax": price_with_tax})
    return item_dict
```

When a client sends a POST request with a JSON body like `{"name": "Widget", "price": 35.99, "tax": 3.60}`, FastAPI automatically parses the JSON, validates it against the `Item` model, and passes the validated object to the handler. If `description` is omitted, it defaults to `None`. If `tax` is omitted, it defaults to `0.0`. If `name` or `price` is missing, a 422 Unprocessable Entity response is returned.

## Field Validation

The `Field()` function from Pydantic lets you add constraints and metadata to individual model fields:

```python
from pydantic import BaseModel, Field

class Item(BaseModel):
    name: str = Field(
        min_length=1,
        max_length=100,
        description="The name of the item",
    )
    description: str | None = Field(
        default=None,
        max_length=500,
        description="An optional text description",
    )
    price: float = Field(
        gt=0,
        le=1_000_000,
        description="Price must be greater than 0 and at most 1,000,000",
    )
    quantity: int = Field(
        default=1,
        ge=1,
        le=9999,
        description="Quantity between 1 and 9999",
    )
```

Pydantic validates all constraints at request time. The `gt`, `ge`, `lt`, `le` parameters mirror the same semantics as FastAPI's `Path()` and `Query()`. The `min_length` and `max_length` parameters work on string fields.

## Nested Models

Pydantic models can contain other models, lists, and complex nested structures:

```python
from pydantic import BaseModel, HttpUrl

class Image(BaseModel):
    url: HttpUrl
    name: str
    width: int = Field(ge=1, le=10000)
    height: int = Field(ge=1, le=10000)

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tags: list[str] = []
    images: list[Image] = []

class Offer(BaseModel):
    name: str
    description: str | None = None
    items: list[Item]
    discount_percent: float = Field(ge=0, le=100)
```

FastAPI validates the entire nested structure recursively. If any nested field fails validation, the error response includes the exact path to the invalid field (e.g., `body -> items -> 0 -> images -> 1 -> url`).

## Combining Body, Path, and Query Parameters

You can accept all three parameter types in a single endpoint:

```python
from fastapi import FastAPI, Path, Query
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    price: float

@app.put("/items/{item_id}")
async def update_item(
    item_id: int = Path(ge=1, le=10000),
    q: str | None = Query(default=None, max_length=50),
    item: Item = ...,
):
    result = {"item_id": item_id, **item.model_dump()}
    if q:
        result["q"] = q
    return result
```

FastAPI determines the source of each parameter by these rules: if the parameter name appears in the path string, it is a path parameter; if the type is a Pydantic model (or annotated with `Body()`), it comes from the request body; otherwise, it is a query parameter.

## Multiple Body Parameters

When you need multiple distinct objects in the request body, declare multiple Pydantic model parameters:

```python
from fastapi import Body

class Item(BaseModel):
    name: str
    price: float

class User(BaseModel):
    username: str
    email: str

@app.put("/items/{item_id}")
async def update_item(
    item_id: int,
    item: Item,
    user: User,
    importance: int = Body(gt=0, le=5),
):
    return {"item_id": item_id, "item": item, "user": user, "importance": importance}
```

The expected JSON body becomes `{"item": {...}, "user": {...}, "importance": 3}`. Each model is keyed by its parameter name. The `Body()` function embeds a singular value inside the body alongside the models, rather than treating it as a query parameter. The maximum request body size is controlled by the ASGI server; Uvicorn defaults to approximately 1 MB.