Перейти до змісту

Тіло запиту

Коли вам потрібно надіслати дані з клієнта (скажімо, браузера) до вашого API, ви надсилаєте їх як тіло запиту.

Тіло запиту — це дані, надіслані клієнтом до вашого API. Тіло відповіді — це дані, які ваш API надсилає клієнту.

Ваш API майже завжди має надсилати тіло відповіді. Але клієнтам не обов’язково потрібно постійно надсилати тіла запитів.

Щоб оголосити тіло запиту, ви використовуєте Pydantic моделі з усією їх потужністю та перевагами.

Info

Щоб надіслати дані, ви повинні використовувати один із: POST (більш поширений), PUT, DELETE або PATCH.

Надсилання тіла із запитом GET має невизначену поведінку в специфікаціях, проте воно підтримується FastAPI лише для дуже складних/екстремальних випадків використання.

Оскільки це не рекомендується, інтерактивна документація з Swagger UI не відображатиме документацію для тіла запиту під час використання GET, і проксі-сервери в середині можуть не підтримувати її.

Імпортуйте BaseModel від Pydantic

Спочатку вам потрібно імпортувати BaseModel з pydantic:

from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel


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


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item
from fastapi import FastAPI
from pydantic import BaseModel


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


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item

Створіть свою модель даних

Потім ви оголошуєте свою модель даних як клас, який успадковується від BaseModel.

Використовуйте стандартні типи Python для всіх атрибутів:

from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel


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


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item
from fastapi import FastAPI
from pydantic import BaseModel


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


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item

Так само, як і при оголошенні параметрів запиту, коли атрибут моделі має значення за замовчуванням, він не є обов’язковим. В іншому випадку це потрібно. Використовуйте None, щоб зробити його необов'язковим.

Наприклад, ця модель вище оголошує JSON "об'єкт" (або Python dict), як:

{
    "name": "Foo",
    "description": "An optional description",
    "price": 45.2,
    "tax": 3.5
}

...оскільки description і tax є необов'язковими (зі значенням за замовчуванням None), цей JSON "об'єкт" також буде дійсним:

{
    "name": "Foo",
    "price": 45.2
}

Оголоси її як параметр

Щоб додати модель даних до вашої операції шляху, оголосіть її так само, як ви оголосили параметри шляху та запиту:

from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel


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


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item
from fastapi import FastAPI
from pydantic import BaseModel


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


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    return item

...і вкажіть її тип як модель, яку ви створили, Item.

Результати

Лише з цим оголошенням типу Python FastAPI буде:

  • Читати тіло запиту як JSON.
  • Перетворювати відповідні типи (якщо потрібно).
  • Валідувати дані.
    • Якщо дані недійсні, він поверне гарну та чітку помилку, вказуючи, де саме і які дані були неправильними.
  • Надавати отримані дані у параметрі item.
    • Оскільки ви оголосили його у функції як тип Item, ви також матимете всю підтримку редактора (автозаповнення, тощо) для всіх атрибутів та їх типів.
  • Генерувати JSON Schema визначення для вашої моделі, ви також можете використовувати їх де завгодно, якщо це має сенс для вашого проекту.
  • Ці схеми будуть частиною згенерованої схеми OpenAPI і використовуватимуться автоматичною документацією інтерфейсу користувача.

Автоматична документація

Схеми JSON ваших моделей будуть частиною вашої схеми, згенерованої OpenAPI, і будуть показані в інтерактивній API документації:

А також використовуватимуться в API документації всередині кожної операції шляху, якій вони потрібні:

Підтримка редактора

У вашому редакторі, всередині вашої функції, ви будете отримувати підказки типу та завершення скрізь (це б не сталося, якби ви отримали dict замість моделі Pydantic):

Ви також отримуєте перевірку помилок на наявність операцій з неправильним типом:

Це не випадково, весь каркас був побудований навколо цього дизайну.

І він був ретельно перевірений на етапі проектування, перед будь-яким впровадженням, щоб переконатися, що він працюватиме з усіма редакторами.

Були навіть деякі зміни в самому Pydantic, щоб підтримати це.

Попередні скріншоти були зроблені у Visual Studio Code.

Але ви отримаєте ту саму підтримку редактора у PyCharm та більшість інших редакторів Python:

Tip

Якщо ви використовуєте PyCharm як ваш редактор, ви можете використати Pydantic PyCharm Plugin.

Він покращує підтримку редакторів для моделей Pydantic за допомогою:

  • автозаповнення
  • перевірки типу
  • рефакторингу
  • пошуку
  • інспекції

Використовуйте модель

Усередині функції ви можете отримати прямий доступ до всіх атрибутів об’єкта моделі:

from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel


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


app = FastAPI()


@app.post("/items/")
async def create_item(item: Item):
    item_dict = item.dict()
    if item.tax:
        price_with_tax = item.price + item.tax
        item_dict.update({"price_with_tax": price_with_tax})
    return item_dict
from fastapi import FastAPI
from pydantic import BaseModel


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


app = FastAPI()


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

Тіло запиту + параметри шляху

Ви можете одночасно оголошувати параметри шляху та тіло запиту.

FastAPI розпізнає, що параметри функції, які відповідають параметрам шляху, мають бути взяті з шляху, а параметри функції, які оголошуються як моделі Pydantic, взяті з тіла запиту.

from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel


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


app = FastAPI()


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    return {"item_id": item_id, **item.dict()}
from fastapi import FastAPI
from pydantic import BaseModel


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


app = FastAPI()


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    return {"item_id": item_id, **item.dict()}

Тіло запиту + шлях + параметри запиту

Ви також можете оголосити параметри тіло, шлях і запит одночасно.

FastAPI розпізнає кожен з них і візьме дані з потрібного місця.

from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel


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


app = FastAPI()


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, q: Union[str, None] = None):
    result = {"item_id": item_id, **item.dict()}
    if q:
        result.update({"q": q})
    return result
from fastapi import FastAPI
from pydantic import BaseModel


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


app = FastAPI()


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, q: str | None = None):
    result = {"item_id": item_id, **item.dict()}
    if q:
        result.update({"q": q})
    return result

Параметри функції будуть розпізнаватися наступним чином:

  • Якщо параметр також оголошено в шляху, він використовуватиметься як параметр шляху.
  • Якщо параметр має сингулярний тип (наприклад, int, float, str, bool тощо), він буде інтерпретуватися як параметр запиту.
  • Якщо параметр оголошується як тип Pydantic моделі, він інтерпретується як тіло запиту.

Note

FastAPI буде знати, що значення "q" не є обов'язковим через значення за замовчуванням "= None".

Optional у Optional[str] не використовується FastAPI, але дозволить вашому редактору надати вам кращу підтримку та виявляти помилки.

Без Pydantic

Якщо ви не хочете використовувати моделі Pydantic, ви також можете використовувати параметри Body. Перегляньте документацію для Тіло – Кілька параметрів: сингулярні значення в тілі.