FastAPI
FastAPI — тонкий слой, а не фреймворк «со всем в комплекте». Он берёт Starlette для маршрутизации поверх ASGI и Pydantic для валидации, добавляет внедрение зависимостей и генерацию OpenAPI — и на этом заканчивается. ORM, миграций, админки в нём нет и не будет. Отсюда первое, что стоит понять про него: скорость даёт не код самого FastAPI, а конкурентная модель ASGI плюс скомпилированное ядро Pydantic, и обе эти вещи легко выключить одной строкой в своём коде.
Вторая особенность — почти вся работа фреймворка привязана к сигнатуре функции. Имя и тип параметра решают, откуда он придёт: из пути, из строки запроса или из тела. Depends() в сигнатуре — это команда вызвать чужую функцию раньше вашей. async def против def — это выбор между циклом событий и пулом потоков, сделанный одним ключевым словом. Именно поэтому ошибки здесь такие тихие: неверная аннотация — это не синтаксическая ошибка, а другое поведение в рантайме, которое проявится под нагрузкой или в проде. Слои ниже разбирают эти механизмы по одному — от места FastAPI среди фреймворков к устройству запроса и дальше к тому, что происходит после ответа.
Карта темы
- FastAPI и Django — что даёт фреймворк — «со всем в комплекте» против тонкого слоя, что вы берёте на себя и как выбирать по задаче.
- ASGI, цикл событий и Starlette — чем ASGI отличается от WSGI, кто держит соединения и где здесь middleware.
- Путь, query и тело — как FastAPI решает — точное правило привязки параметра по имени и типу и маркеры, которые его переопределяют.
- Модели Pydantic и код 422 — приведение типов, момент валидации и почему неверные данные клиента не становятся ошибкой сервера.
- response_model и фильтрация ответа — почему это не документация, а фильтр, и что он отрезает по дороге к клиенту.
- Depends, под-зависимости и yield — порядок вызова, кэш на время запроса и точный момент очистки ресурса.
- async def против def — цикл событий и пул потоков, цена блокирующего вызова и как её не заплатить.
- BackgroundTasks и настоящая очередь — что выполняется в том же процессе, что теряется при перезапуске и где проходит граница.
- Аутентификация по JWT — извлечение токена, проверка подписи и срока, и почему отзыв требует отдельного решения.
Частые ошибки и ловушки
| Ошибка | Последствие |
|---|---|
Синхронный клиент (requests, драйвер базы) внутри async def | Вызов держит единственный цикл событий воркера всё время ожидания — растут задержки у всех маршрутов, включая те, что не делают ничего, при простаивающем процессоре |
Считать response_model документацией | Он реально пересобирает ответ: поля, которых в модели нет, отбрасываются. Обратная сторона — поле с паролем, попавшее в модель, уходит клиенту, и никакой аннотацией это не остановить |
Ждать 422 от модели, собранной руками внутри обработчика | Встроенный обработчик ловит RequestValidationError только на входе; исключение из тела обработчика становится 500 |
Класть работу под процессор в BackgroundTasks | Задача идёт в том же процессе после ответа и удерживает интерпретатор — воркер снова перестаёт обслуживать запросы |
| Рассчитывать, что фоновая задача переживёт перезапуск | Ни очереди, ни сохранения, ни повторов: при переезде процесса задача просто исчезает |
Использовать сессию из зависимости с yield внутри фоновой задачи | Teardown выполняется после отправки ответа и до фоновых задач, поэтому сессия там уже закрыта |
Бросать HTTPException после yield | Ответ клиенту уже ушёл — изменить его нечем, исключение только попадёт в лог |
Декодировать JWT без проверки подписи или без exp | Токен становится предъявительским: любой подделанный или просроченный проходит как валидный |
| Ждать, что одиночный скаляр попадёт в тело запроса | По правилу привязки скалярный тип уходит в query-параметры; чтобы он стал телом, нужен Body(embed=True) |
response_model на горячем списочном эндпоинте | Каждая строка собирается дважды — сперва ORM, затем модель; на больших выдачах этот проход и определяет время ответа |
Значение для собеседований
FastAPI спрашивают у middle-кандидатов на бэкенд почти всегда, и разговор быстро уходит с фреймворка на конкурентность. Начинают с безобидного — «что такое FastAPI», «что делает Depends», «зачем Pydantic», — но настоящая проверка идёт следом: «а что будет, если внутри async def вызвать requests.get». Здесь и выясняется, работал ли человек с нагрузкой. Кандидат, который хоть раз ловил заблокированный цикл событий, отвечает не определением, а описанием симптома — растут задержки у посторонних маршрутов, а процессор простаивает.
Второй такой же индикатор — вопрос про response_model. Ответ «это для документации» закрывает тему не в вашу пользу; ждут понимания, что объект пересобирается и что именно это защищает от утечки полей. Третий — граница между BackgroundTasks и очередью на брокере: правильный ответ звучит как перечисление того, чего у фоновой задачи нет (сохранения, повторов, изоляции процесса), а не как «для лёгких задач».
Дальше идут вопросы на аккуратность. Про привязку параметров проверяют, назовёте ли вы правило по имени и типу, а не по порядку аргументов. Про 422 — понимаете ли вы, что валидация идёт до обработчика, и почему это делает ошибку клиентской, а не серверной. Про JWT почти всегда есть скрытая вторая часть — как отозвать токен; ответ «никак, если не завести список отзыва или короткий срок жизни» ценится выше пересказа схемы OAuth2. Типичный провал везде один и тот же: кандидат верно пересказывает документацию, но не может назвать, что именно сломается под нагрузкой.