Middleware и зависимости
Два механизма, которые отличают продовый сервис от учебного: middleware (общий конвейер вокруг каждого запроса) и DI (dependency injection) (сборка зависимостей эндпоинта). Собес проверяет, понимаешь ли ты порядок исполнения - потому что перепутанный порядок middleware тихо ломает auth, а забытый teardown в зависимости течёт соединениями.
Типовые формулировки: «зачем и в каком порядке middleware?», «как FastAPI собирает зависимости?», «что делает yield в Depends».
Middleware - конвейер, порядок решает
Middleware - код в конвейере между приёмом запроса и вью: он видит каждый запрос ДО обработчика и каждый ответ ПОСЛЕ. Туда выносят сквозное: аутентификацию, логи, CORS (cross-origin resource sharing), сжатие. Внешний middleware исполняется первым на входе и последним на выходе - как луковица.
Поэтому порядок важен: auth должен стоять раньше кода, что ждёт пользователя; сжатие - снаружи, чтобы жать уже готовый ответ. Middleware может и вернуть ответ сам, не вызвав следующий слой - тогда вью не выполнится вовсе. Так работают ранние отказы: 401, 429, CORS-preflight.
// Перепутанный порядок ломает зависимости или вовсе пропускает проверки это тихий баг, тесты happy path его не ловят.
- middleware
- прослойка, оборачивающая обработку каждого запроса
- short-circuit
- middleware вернул ответ, не пустив запрос дальше
Depends-граф и teardown через yield
В FastAPI зависимости образуют граф: get_current_user зависит от get_db, эндпоинт - от get_current_user. Общие узлы кэшируются в пределах одного запроса, поэтому get_db выполнится один раз, даже если его требуют несколько зависимостей.
Зависимость-генератор с yield даёт setup/teardown: значение до yield подставляется в эндпоинт, а код после yield выполняется на завершении запроса - закрыть сессию, вернуть соединение в пул. Забыл teardown (не сделал зависимость через yield) - сессия или соединение не вернётся в пул, и он исчерпается.
// Это тот же паттерн, что contextmanager: гарантированная уборка, привязанная к жизни запроса.
def get_db():
db = Session()
try: yield db # <- в эндпоинт
finally: db.close() # <- teardown на конец запроса- Depends-граф
- цепочка зависимостей FastAPI с кэшем на запрос
- yield-зависимость
- setup до yield, teardown после - на конец запроса
Как отвечать: «Что делает yield в зависимости FastAPI?»
Он превращает зависимость в setup/teardown вокруг запроса. Код до yield это подготовка: открыть сессию БД, взять соединение из пула; то, что я отдаю через yield, попадёт в эндпоинт. А код после yield FastAPI выполнит гарантированно на завершении запроса, даже если внутри было исключение - там я закрываю сессию и возвращаю соединение в пул. Это ровно семантика контекстного менеджера, привязанная к жизни запроса. Если забыть teardown и просто вернуть сессию через return, соединения не вернутся в пул и он быстро исчерпается под нагрузкой.
Объяснена двухфазность (до/после yield), гарантия выполнения при исключении, аналогия с contextmanager и конкретное последствие пропуска - видно понимание жизненного цикла, а не заученный синтаксис.
На чём валят
- −Перепутанный порядок middleware ломает зависимости (auth после кода, что ждёт юзера) или пропускает проверки.
- −Забыть teardown в yield-зависимости: сессия/соединение не вернётся в пул, и он исчерпается.
- −Ждать, что вью выполнится, когда middleware уже вернул 401 без передачи дальше по конвейеру.
- −Полагать, что зависимость выполнится на каждое использование: в пределах запроса общий узел графа кэшируется.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 13, остальные разбираются в тренажёре.
- Что такое middleware в веб-фреймворке?A)Прослойка, оборачивающая обработку каждого запросаB)Клиентская библиотека для вызова внешнего API из приложенияC)Формат обмена сообщениями между микросервисами системыD)Отдельная база данных для промежуточных результатов вычислений
показать ответ и разбор
+A)Прослойка, оборачивающая обработку каждого запроса// разбор: Middleware — код в конвейере между приёмом запроса и вью: он видит каждый запрос до обработчика и каждый ответ после. Туда кладут аутентификацию, логирование, CORS, сжатие. Это единая точка для сквозной логики, не размазанной по эндпоинтам.
- Почему порядок middleware важен?A)Порядок влияет только на время старта приложения при запускеB)Важен лишь для middleware, пишущих запросы в общий логC)Каждый оборачивает следующий — очередь меняет поведениеD)Фреймворк игнорирует порядок и применяет middleware разом
показать ответ и разбор
+C)Каждый оборачивает следующий — очередь меняет поведение// разбор: Middleware — вложенные обёртки: внешний выполняется первым на входе и последним на выходе. Аутентификация должна стоять до кода, который ждёт пользователя; сжатие — снаружи, чтобы сжать финальный ответ. Перестановка ломает зависимости или пропускает проверки безопасности.
- FastAPI: может ли зависимость
Dependsсама зависеть от другой зависимости?A)Нет, Depends работает исключительно на верхнем уровне эндпоинтаB)Нет, для вложенности зависимость надо объявить классом, а не функциейC)Да, но только если обе объявлены в одном и том же файлеD)Да, зависимости выстраиваются в цепочку и графпоказать ответ и разбор
+D)Да, зависимости выстраиваются в цепочку и граф// разбор: Depends образуют граф: get_current_user может сам зависеть от get_db, а эндпоинт — от get_current_user. FastAPI резолвит цепочку и кэширует общие узлы в пределах запроса: один get_db на запрос, даже если его просят несколько зависимостей.
- Зависимость FastAPI написана через
yield. Что исполнится после yield?A)Повторная валидация тела запроса непосредственно перед ответомB)Ничего: код после yield недостижим по самому определениюC)Код очистки на выходе из запроса — закрыть сессиюD)Обработка следующего запроса того же клиента по очередипоказать ответ и разбор
+C)Код очистки на выходе из запроса — закрыть сессию// разбор: Зависимость-генератор с yield отдаёт значение до yield, а код после него FastAPI выполняет при завершении запроса — идеально для teardown: закрыть сессию БД, вернуть соединение в пул, снять лок. Аналог контекстного менеджера, встроенный в жизненный цикл запроса.
- Middleware аутентификации вернул 401, не передав управление дальше по цепочке. Что произойдёт?A)Вью всё равно выполнится, а 401 будет лишь пометкой в ответеB)Запрос не дойдёт до вью — цепочка замкнута ответомC)Фреймворк автоматически повторит запрос в обход middlewareD)Ответ уйдёт пустым, потому что статус клиентом игнорируется
показать ответ и разбор
+B)Запрос не дойдёт до вью — цепочка замкнута ответом// разбор: Middleware волен вернуть ответ сам, не передавая управление дальше: тогда вью и внутренние middleware не выполнятся — запрос «замкнут» на этой прослойке. Так работают ранние отказы: 401 без пользователя, 429 при рейт-лимите, ответ на CORS-preflight.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.