# Unit 12: Request Body - List Fields and Nested Models

## Introduction

In FastAPI, you can define request bodies with complex structures using Pydantic models. These can include fields and nested models. In the following sections, this unit will show how to implement list fields and nested models.

## List fields

Let's take a look at the following program:

{% code lineNumbers="true" %}

```python
# Note: This program is implemented in Python 3.12
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

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


@app.post("/update-item/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item, "message": "Item updated successfully"}
    return results
```

{% endcode %}

{% hint style="info" %}
You should note that the above program is implemented in Python 3.12. If you are using Python before version 3.9, the `List` declaration is as follows:

`from typing import List`

`my_list: List[str]`
{% endhint %}

To evaluate the program, you can compose a request in Postman as shown in Fig. 1. The request body can be as follows:

```json
{
    "name": "Green Apple",
    "description": "A type of fruit",
    "price": 50000,
    "tax": 2500,
    "tags": ["fruit", "apple"]
}
```

<figure><img src="/files/A3Vy5ZhqMZoRn4ogakqA" alt=""><figcaption><p>Fig. 1. Example of a quest in Postman</p></figcaption></figure>

{% hint style="info" %}
In Python, a `list` allows duplicate elements and maintains their order, while a `set` ensures element uniqueness without any guaranteed order.
{% endhint %}

## Nested models

In the following program, we define two classes, i.e., `Image` and `Item`, and they have a HAS-A relationship. In `Image` class, the `metadata` is declared as a list of dictionary (key-value pairs).

{% code lineNumbers="true" %}

```python
# Note: This program is implemented in Python 3.12
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Image(BaseModel):
    url: str
    metadata: list[dict[str, str]]

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


@app.post("/update-item/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item, "message": "Item updated successfully"}
    return results
```

{% endcode %}

The request body to evaluate the above program is as follows. You should note how we compose the `metadata` values. Fig. 2 shows the results when evaluating the program in Postman.

```json
{
    "name": "Green Apple",
    "description": "A type of fruit",
    "price": 50000,
    "tax": 2500,
    "tags": [
        "fruit",
        "apple"
    ],
    "image": {
        "url": "example.com",
        "metadata": [
            {
                "File type": "JPEG",
                "MIME type": "image/jpeg"
            }
        ]
    }
}
```

<figure><img src="/files/r0mV03isOdsV5pJKm0Qf" alt=""><figcaption><p>Fig. 2. Example of a quest in Postman</p></figcaption></figure>

## Example program

In this example:

* We define a Pydantic model `Item` with fields `name`, `description`, `price`, and `tax`.
* We then define another Pydantic model `Order` that contains a list of `Item` objects along with `customer_name` and `shipping_address`.
* In the route `/order/`, we accept POST requests with a request body of type `Order`.
* When a request is made to `/order/`, FastAPI automatically validates the request body against the `Order` model and gives you an instance of `Order` in the route function `create_order`.

{% code lineNumbers="true" %}

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

app = FastAPI()

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

class Order(BaseModel):
    items: list[Item]
    customer_name: str
    shipping_address: str

@app.post("/order/")
async def create_order(order: Order):
    return {"order_details": order}
```

{% endcode %}

***

## Summary

In this unit, we have introduced how to enhance request body in FastAPI to allow the server program to capture more complex inputs using list fields and nested models in combination with Pydantic model.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://fastapi-docs.duonghuuphuc.com/unit-12-request-body-list-fields-and-nested-models.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
