Модуль 12 · Урок 45 із 58
Pydantic у FastAPI: request і response models
Type hint стає API boundary лише тоді, коли команда усвідомлює coercion, constraints, unknown fields і різницю між input, domain та public output. Один ORM object не повинен автоматично бути і request body, і database model, і response.
Безпечна FastAPI-практика модуля 12
Пакет містить synthetic SprintBoard API, Pydantic v2 models, dependencies, Problem Details, middleware, TestClient і OpenAPI contract tests. Він не відкриває зовнішню мережу під час tests, не містить authentication substitutes, персональних чи production-даних, credentials або production endpoints.
Model гарантує форму результату validation
Pydantic BaseModel читає недовірені input values, перетворює або відхиляє їх і створює model instance з оголошеними types та constraints. Він гарантує output після validation, а не те, що raw input уже мав потрібний Python type.
from pydantic import BaseModel, ConfigDict, Field
class TaskCreate(BaseModel):
model_config = ConfigDict(extra="forbid")
title: str = Field(min_length=2, max_length=100)
priority: int = Field(ge=1, le=5)
labels: list[str] = Field(default_factory=list, max_length=10)default_factory створює окрему collection для кожного instance. extra="forbid" робить typo або неочікуване field явним failure замість тихого ігнорування.
Coercion має бути свідомою
За замовчуванням Pydantic може перетворити сумісні values, наприклад numeric string на integer. Це зручно для query parameters, але ризиковано для identifiers, money або security-sensitive flags. Для таких fields застосовують strict types або strict=True і тестують JSON та Python validation modes.
None, але default визначає requiredness.Input і output потребують різних models
TaskCreate описує те, що client може надіслати. TaskPublic описує те, що client може отримати. Internal fields на кшталт password hash, owner note, cost або moderation flag не входять до public output.
class TaskPublic(BaseModel):
id: int
title: str
priority: int
status: str
@app.post(
"/tasks",
response_model=TaskPublic,
status_code=201,
)
async def create_task(payload: TaskCreate):
return repository.create(payload.model_dump())FastAPI використовує response model для OpenAPI, serialization, validation та filtering. Якщо application повертає missing required field, це server bug; якщо повертає зайве internal field, response filtering не випустить його за заявлений contract.
Nested contract і serialization перевіряються окремо
Nested models дозволяють виразити structured data, але payload depth, list size та string length мають bounded policy. model_dump() повертає Python structures; model_dump_json() серіалізує JSON. Alias, exclude і computed field змінюють wire representation, тому покриваються tests.
Validation не є authorization
Валідний owner_id не доводить, що caller має право діяти від імені owner. Authentication та authorization — окрема trust boundary наступного модуля.
Error response не повинен віддзеркалювати secrets
Default validation error корисний, але custom handler не має повертати весь raw body, headers або exception string без review. Public issues можуть містити safe location і stable error type; raw payload лишається поза response та проходить redaction у захищеній telemetry.
- Розділіть create, update, public і internal models.
- Визначте coercion та extra-field policy.
- Bounded constraints додайте на transport boundary.
- Перевірте positive, missing, wrong type, boundary й extra cases.
- Окремо доведіть, що output не містить internal fields.
Методичні джерела
Урок, сценарії, пояснення й вправи створені SEOWORK. Посилання ведуть на офіційну документацію framework та стандартів.
Закріпіть матеріал уроку
Три сценарні питання. Для зарахування уроку потрібно дати щонайменше дві правильні відповіді.