сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · FastAPI, Django и API

Middleware и зависимости

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, остальные разбираются в тренажёре.

  1. #middleware_di1 / 5
    Что такое middleware в веб-фреймворке?
    A)Прослойка, оборачивающая обработку каждого запроса
    B)Клиентская библиотека для вызова внешнего API из приложения
    C)Формат обмена сообщениями между микросервисами системы
    D)Отдельная база данных для промежуточных результатов вычислений
    показать ответ и разбор
    +A)Прослойка, оборачивающая обработку каждого запроса

    // разбор: Middleware — код в конвейере между приёмом запроса и вью: он видит каждый запрос до обработчика и каждый ответ после. Туда кладут аутентификацию, логирование, CORS, сжатие. Это единая точка для сквозной логики, не размазанной по эндпоинтам.

  2. #middleware_di2 / 5
    Почему порядок middleware важен?
    A)Порядок влияет только на время старта приложения при запуске
    B)Важен лишь для middleware, пишущих запросы в общий лог
    C)Каждый оборачивает следующий — очередь меняет поведение
    D)Фреймворк игнорирует порядок и применяет middleware разом
    показать ответ и разбор
    +C)Каждый оборачивает следующий — очередь меняет поведение

    // разбор: Middleware — вложенные обёртки: внешний выполняется первым на входе и последним на выходе. Аутентификация должна стоять до кода, который ждёт пользователя; сжатие — снаружи, чтобы сжать финальный ответ. Перестановка ломает зависимости или пропускает проверки безопасности.

  3. #middleware_di3 / 5
    FastAPI: может ли зависимость Depends сама зависеть от другой зависимости?
    A)Нет, Depends работает исключительно на верхнем уровне эндпоинта
    B)Нет, для вложенности зависимость надо объявить классом, а не функцией
    C)Да, но только если обе объявлены в одном и том же файле
    D)Да, зависимости выстраиваются в цепочку и граф
    показать ответ и разбор
    +D)Да, зависимости выстраиваются в цепочку и граф

    // разбор: Depends образуют граф: get_current_user может сам зависеть от get_db, а эндпоинт — от get_current_user. FastAPI резолвит цепочку и кэширует общие узлы в пределах запроса: один get_db на запрос, даже если его просят несколько зависимостей.

  4. #middleware_di4 / 5
    Зависимость FastAPI написана через yield. Что исполнится после yield?
    A)Повторная валидация тела запроса непосредственно перед ответом
    B)Ничего: код после yield недостижим по самому определению
    C)Код очистки на выходе из запроса — закрыть сессию
    D)Обработка следующего запроса того же клиента по очереди
    показать ответ и разбор
    +C)Код очистки на выходе из запроса — закрыть сессию

    // разбор: Зависимость-генератор с yield отдаёт значение до yield, а код после него FastAPI выполняет при завершении запроса — идеально для teardown: закрыть сессию БД, вернуть соединение в пул, снять лок. Аналог контекстного менеджера, встроенный в жизненный цикл запроса.

  5. #middleware_di5 / 5
    Middleware аутентификации вернул 401, не передав управление дальше по цепочке. Что произойдёт?
    A)Вью всё равно выполнится, а 401 будет лишь пометкой в ответе
    B)Запрос не дойдёт до вью — цепочка замкнута ответом
    C)Фреймворк автоматически повторит запрос в обход middleware
    D)Ответ уйдёт пустым, потому что статус клиентом игнорируется
    показать ответ и разбор
    +B)Запрос не дойдёт до вью — цепочка замкнута ответом

    // разбор: Middleware волен вернуть ответ сам, не передавая управление дальше: тогда вью и внутренние middleware не выполнятся — запрос «замкнут» на этой прослойке. Так работают ранние отказы: 401 без пользователя, 429 при рейт-лимите, ответ на CORS-preflight.

дальше

Теорию прочитали. Навык ставится повторением

В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.