РекомендуетсяFastAPIPydantic 2Python

FastAPI: routers, модели и жизненный цикл ресурсов

Определите один явный composition root FastAPI, подключайте APIRouter и описывайте вход/выход моделями. Ресурсы процесса создаются и закрываются в lifespan, зависимости запроса — через Depends.

Опубликовано Проверено Изменено

Плохо

# Импорт модуля сразу открывает соединение и скрыто создает отдельное приложение.
db = connect_to_database()
app = FastAPI()
@app.get("/orders")
def orders():
    return db.query("select * from orders")

Хорошо

from fastapi import APIRouter, FastAPI
from pydantic import BaseModel
 
class HealthResponse(BaseModel):
    status: str
 
router = APIRouter(prefix="/health", tags=["health"])
 
@router.get("", response_model=HealthResponse)
def read_health() -> HealthResponse:
    return HealthResponse(status="ok")
 
app = FastAPI()
app.include_router(router)

Почему это важно

Роутер, который нигде не включен, не создает endpoint в нужном приложении. Явная сборка приложения и управление ресурсами позволяют тестам подменять зависимости и корректно закрывать соединения.

Когда применять

Современный FastAPI с Pydantic 2; зафиксируйте версии FastAPI/Starlette/Pydantic/Python в приложении. Пример полностью объявляет простой endpoint без внешнего ресурса. В большем проекте перенесите router в модуль, а include_router оставьте в composition root. Функции/модули — snake_case, модели — CapWords по Python-соглашению.

Pydantic-модель входа и response_model имеют разные роли. Не возвращайте ORM/entity целиком, если публичный ответ ограничен; response model не заменяет право доступа. Согласуйте coercion, optional/null и запрет extra полей согласно API, не считайте любое Pydantic-поле строгим по умолчанию.

Depends используют для контекста/ресурса запроса и его подмены в тесте; не вызывайте dependency как обычную функцию, ожидая внедрения. Ресурсы уровня приложения открывают до yield и закрывают после yield в lifespan; их не создают побочным эффектом импорта. Если lifespan задан, не рассчитывайте одновременно на старые startup/shutdown handlers.

Синхронные и async зависимости выбираются по характеру I/O. Отдельная папка services/repositories допустима при собственной ответственности, но FastAPI ее не требует. В OpenAPI проверяются все реально включенные routers и модели, а не только импорты.

Кто что делает

Человек

Утверждает схему API, область жизни ресурсов и границы роутеров.

AI-агент

Показывает include_router и контракт моделей, проверяет startup/shutdown и подмену зависимостей.

Как проверить у себя

Вход и действиеОжидаемый результатСвидетельство
GET /health в созданном приложении200 и объект {"status":"ok"} по response modelTestClient/HTTP
Router забыли include_routerПроверка OpenAPI/маршрута выявляет отсутствие endpointНегативная конфигурационная проверка
Dependency заменена в тестеИспользован контролируемый ресурс, production-соединение не открытоdependency_overrides и счетчик
Startup/shutdown, в том числе при ошибкеРесурс закрыт, импорт модуля не делает I/OTestClient как context manager и lifecycle log

Модульный импорт и AST-проверка подтверждают синтаксис, но не исполнение lifespan или HTTP-маршрута.

ПервоисточникиИстория изменений на GitHub

Дата проверки отражает содержательную сверку. Синхронизация сайта не обновляет её автоматически.