Если использовать блок try в зависимости с yield, то будет получено всякое исключение, которое было выброшено при использовании зависимости.
Например, если какой-то код в какой-то момент в середине, в другой зависимости или в функции операции пути, сделал "откат" транзакции базы данных или создал любую другую ошибку, то вы получите исключение в своей зависимости.
Таким образом, можно искать конкретное исключение внутри зависимости с помощью except SomeException.
Таким же образом можно использовать finally, чтобы убедиться, что обязательные шаги при выходе выполнены, независимо от того, было ли исключение или нет.
Вы видели, что можно использовать зависимости с yield совместно с блоком try, отлавливающие исключения.
Таким же образом вы можете поднять исключение HTTPException или что-то подобное в завершающем коде, после yield.
Код выхода в зависимостях с yield выполняется после отправки ответа, поэтому Обработчик исключений уже будет запущен. В коде выхода (после yield) нет ничего, перехватывающего исключения, брошенные вашими зависимостями.
Таким образом, если после yield возникает HTTPException, то стандартный (или любой пользовательский) обработчик исключений, который перехватывает HTTPException и возвращает ответ HTTP 400, уже не сможет перехватить это исключение.
Благодаря этому все, что установлено в зависимости (например, сеанс работы с БД), может быть использовано, например, фоновыми задачами.
Фоновые задачи выполняются после отправки ответа. Поэтому нет возможности поднять HTTPException, так как нет даже возможности изменить уже отправленный ответ.
Но если фоновая задача создает ошибку в БД, то, по крайней мере, можно сделать откат или чисто закрыть сессию в зависимости с помощью yield, а также, возможно, занести ошибку в журнал или сообщить о ней в удаленную систему отслеживания.
Если у вас есть код, который, как вы знаете, может вызвать исключение, сделайте самую обычную/"питонячью" вещь и добавьте блок try в этот участок кода.
Если у вас есть пользовательские исключения, которые вы хотите обрабатывать до возврата ответа и, возможно, модифицировать ответ, даже вызывая HTTPException, создайте Cобственный обработчик исключений.
Подсказка
Вы все еще можете вызывать исключения, включая HTTPException, доyield. Но не после.
Последовательность выполнения примерно такая, как на этой схеме. Время течет сверху вниз. А каждый столбец - это одна из частей, взаимодействующих с кодом или выполняющих код.
Дополнительная информация
Клиенту будет отправлен только один ответ. Это может быть один из ответов об ошибке или это будет ответ от операции пути.
После отправки одного из этих ответов никакой другой ответ не может быть отправлен.
Подсказка
На этой диаграмме показано "HttpException", но вы также можете вызвать любое другое исключение, для которого вы создаете Пользовательский обработчик исключений.
Если вы создадите какое-либо исключение, оно будет передано зависимостям с yield, включая HttpException, а затем снова обработчикам исключений. Если для этого исключения нет обработчика исключений, то оно будет обработано внутренним "ServerErrorMiddleware" по умолчанию, возвращающим код состояния HTTP 500, чтобы уведомить клиента, что на сервере произошла ошибка.
Зависимости с yield, HTTPException и фоновыми задачами¶
Внимание
Скорее всего, вам не нужны эти технические подробности, вы можете пропустить этот раздел и продолжить ниже.
Эти подробности полезны, главным образом, если вы использовали версию FastAPI до 0.106.0 и использовали ресурсы из зависимостей с yield в фоновых задачах.
До версии FastAPI 0.106.0 вызывать исключения после yield было невозможно, код выхода в зависимостях с yield выполнялся после отправки ответа, поэтому Обработчик Ошибок уже был бы запущен.
Это было сделано главным образом для того, чтобы позволить использовать те же объекты, "отданные" зависимостями, внутри фоновых задач, поскольку код выхода будет выполняться после завершения фоновых задач.
Тем не менее, поскольку это означало бы ожидание ответа в сети, а также ненужное удержание ресурса в зависимости от доходности (например, соединение с базой данных), это было изменено в FastAPI 0.106.0.
Подсказка
Кроме того, фоновая задача обычно представляет собой независимый набор логики, который должен обрабатываться отдельно, со своими собственными ресурсами (например, собственным подключением к базе данных).
Таким образом, вы, вероятно, получите более чистый код.
Если вы полагались на это поведение, то теперь вам следует создавать ресурсы для фоновых задач внутри самой фоновой задачи, а внутри использовать только те данные, которые не зависят от ресурсов зависимостей с yield.
Например, вместо того чтобы использовать ту же сессию базы данных, вы создадите новую сессию базы данных внутри фоновой задачи и будете получать объекты из базы данных с помощью этой новой сессии. А затем, вместо того чтобы передавать объект из базы данных в качестве параметра в функцию фоновой задачи, вы передадите идентификатор этого объекта, а затем снова получите объект в функции фоновой задачи.
Под капотом" open("./somefile.txt") создаёт объект называемый "контекстным менеджером".
Когда блок with завершается, он обязательно закрывает файл, даже если были исключения.
Когда вы создаете зависимость с помощью yield, FastAPI внутренне преобразует ее в контекстный менеджер и объединяет с некоторыми другими связанными инструментами.
Использование менеджеров контекста в зависимостях с помощью yield¶
Внимание
Это более или менее "продвинутая" идея.
Если вы только начинаете работать с FastAPI, то лучше пока пропустить этот пункт.