Модуль 12 · Урок 46 із 58
FastAPI dependencies, errors і async boundaries
Dependency injection робить request context і infrastructure явними, exception handlers уніфікують public failures, middleware охоплює cross-cutting behavior, а правильна async boundary не дозволяє blocking I/O зупинити event loop.
Безпечна FastAPI-практика модуля 12
Пакет містить synthetic SprintBoard API, Pydantic v2 models, dependencies, Problem Details, middleware, TestClient і OpenAPI contract tests. Він не відкриває зовнішню мережу під час tests, не містить authentication substitutes, персональних чи production-даних, credentials або production endpoints.
Dependency graph замінює приховані globals
Path operation оголошує, що йому потрібен repository, settings або request context, а FastAPI розв’язує dependency graph для кожного request. Dependency може мати власні sub-dependencies та впливати на OpenAPI parameters.
from typing import Annotated
from fastapi import Depends
def get_repository() -> TaskRepository:
return repository
RepositoryDep = Annotated[TaskRepository, Depends(get_repository)]
@app.get("/tasks/{task_id}")
async def get_task(task_id: int, repo: RepositoryDep):
return repo.get(task_id)У tests app.dependency_overrides[get_repository] підміняє production provider isolated fake. Override очищають після test, інакше state протече до наступного scenario.
Resource lifecycle оформлюють через yield
Dependency з yield створює resource, передає його handler і виконує cleanup. Це підходить для database session або scoped client, але transaction policy та exception behavior треба задати явно. Cleanup має працювати й при failure.
def get_session():
session = SessionFactory()
try:
yield session
finally:
session.close()Connection pool є application-scoped infrastructure, а session — request-scoped unit. Створення нового pool на кожен request є дорогою помилкою.
Domain failure мапиться на HTTP один раз
Repository або service може підняти TaskNotFound чи TitleConflict. Web layer перетворює їх на 404/409 і safe structured representation. HTTPException зручний на boundary, але domain core краще не прив’язувати до FastAPI.
Safe Problem Details
Public type, title, status, detail та request-scoped instance не включають SQL, stack trace, credentials, internal paths або raw body.
Request validation failures обробляє RequestValidationError. Handler може нормалізувати shape, але не повинен перетворювати application bug у начебто client error.
Middleware обгортає кожен request
Middleware виконує код до route і після response. Тут доречні request ID, coarse timing, security headers або tracing context. Authorization часто краще виражати dependencies на конкретних routes; один global middleware не знає всіх domain rules.
Кілька middleware утворюють stack: останнє додане є outermost, на request виконується першим, на response — останнім. Order перевіряють test, особливо для CORS, errors і tracing.
def та async def обирають за I/O contract
Якщо library надає awaitable I/O, path operation роблять async def і викликають її через await. Blocking library можна викликати з normal def handler/dependency, який FastAPI запускає у threadpool. Виклик blocking network, filesystem або database code прямо всередині async def блокує event loop.
| Operation | Boundary | Risk |
|---|---|---|
| Async database driver | async def + await | Забутий await |
| Blocking SDK | def або explicit thread offload | Event-loop stall |
| CPU-heavy transform | Queue/process boundary | Threadpool не дає CPU parallelism |
Timeout, cancellation і cleanup є частиною design; просто додати async до function name недостатньо.
Методичні джерела
Урок, сценарії, пояснення й вправи створені SEOWORK. Посилання ведуть на офіційну документацію framework та стандартів.
Закріпіть матеріал уроку
Три сценарні питання. Для зарахування уроку потрібно дати щонайменше дві правильні відповіді.