15 KiB
Зависимости
FastAPI имеет очень мощную, но интуитивную систему Инъекция зависимостей.
Она спроектирована так, чтобы быть очень простой в использовании и облегчать любому разработчику интеграцию других компонентов с FastAPI.
Что такое инъекция зависимостей («Dependency Injection»)
В программировании «Dependency Injection» означает, что у вашего кода (в данном случае у ваших функций обработки пути) есть способ объявить вещи, которые требуются для его работы и использования: «зависимости».
И затем эта система (в нашем случае FastAPI) позаботится о том, чтобы сделать всё необходимое для предоставления вашему коду этих зависимостей (сделать «инъекцию» зависимостей).
Это очень полезно, когда вам нужно:
- Обеспечить общую логику (один и тот же алгоритм снова и снова).
- Разделять соединения с базой данных.
- Обеспечить безопасность, аутентификацию, требования к ролям и т. п.
- И многое другое...
Всё это при минимизации повторения кода.
Первые шаги
Давайте рассмотрим очень простой пример. Он настолько простой, что пока не очень полезен.
Но так мы сможем сосредоточиться на том, как работает система Dependency Injection.
Создайте зависимость, или «dependable» (от чего что-то зависит)
Сначала сосредоточимся на зависимости.
Это просто функция, которая может принимать те же параметры, что и функция обработки пути:
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}
И всё.
2 строки.
И она имеет ту же форму и структуру, что и все ваши функции обработки пути.
Можно думать о ней как о функции обработки пути без «декоратора» (без @app.get("/some-path")
).
И она может возвращать что угодно.
В этом случае эта зависимость ожидает:
- Необязательный query-параметр
q
типаstr
. - Необязательный query-параметр
skip
типаint
, по умолчанию0
. - Необязательный query-параметр
limit
типаint
, по умолчанию100
.
А затем просто возвращает dict
, содержащий эти значения.
/// info | Информация
FastAPI добавил поддержку Annotated
(и начал рекомендовать его использование) в версии 0.95.0.
Если у вас более старая версия, вы получите ошибки при попытке использовать Annotated
.
Убедитесь, что вы обновили версию FastAPI{.internal-link target=_blank} как минимум до 0.95.1, прежде чем использовать Annotated
.
///
Импорт Depends
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}
Объявите зависимость в «зависимом»
Точно так же, как вы используете Body
, Query
и т. д. с параметрами вашей функции обработки пути, используйте Depends
с новым параметром:
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}
Хотя вы используете Depends
в параметрах вашей функции так же, как Body
, Query
и т. д., Depends
работает немного иначе.
В Depends
вы передаёте только один параметр.
Этот параметр должен быть чем-то вроде функции.
Вы не вызываете её напрямую (не добавляйте круглые скобки в конце), просто передаёте её как параметр в Depends()
.
И эта функция принимает параметры так же, как функции обработки пути.
/// tip | Подсказка
В следующей главе вы увидите, какие ещё «вещи», помимо функций, можно использовать в качестве зависимостей.
///
Каждый раз, когда приходит новый запрос, FastAPI позаботится о:
- Вызове вашей зависимости («dependable») с корректными параметрами.
- Получении результата из вашей функции.
- Присваивании этого результата параметру в вашей функции обработки пути.
graph TB
common_parameters(["common_parameters"])
read_items["/items/"]
read_users["/users/"]
common_parameters --> read_items
common_parameters --> read_users
Таким образом, вы пишете общий код один раз, а FastAPI позаботится о его вызове для ваших операций пути.
/// check | Проверка
Обратите внимание, что вам не нужно создавать специальный класс и передавать его куда-то в FastAPI, чтобы «зарегистрировать» его или что-то подобное.
Вы просто передаёте его в Depends
, и FastAPI знает, что делать дальше.
///
Использование зависимости с Annotated
в нескольких местах
В приведённых выше примерах есть небольшое повторение кода.
Когда вам нужно использовать зависимость common_parameters()
, вы должны написать весь параметр с аннотацией типа и Depends()
:
commons: Annotated[dict, Depends(common_parameters)]
Но поскольку мы используем Annotated
, мы можем сохранить это значение Annotated
в переменную и использовать его в нескольких местах:
{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}
/// tip | Подсказка
Это стандартный Python, это называется «type alias», и это не особенность FastAPI.
Но поскольку FastAPI основан на стандартах Python, включая Annotated
, вы можете использовать этот трюк в своём коде. 😎
///
Зависимости продолжат работать как ожидалось, и лучшая часть в том, что информация о типах будет сохранена, а значит, ваш редактор кода продолжит предоставлять автозавершение, встроенные ошибки и т.д. То же относится и к другим инструментам, таким как mypy
.
Это особенно полезно, когда вы используете это в большой кодовой базе, где вы используете одни и те же зависимости снова и снова во многих операциях пути.
Использовать async
или не async
Поскольку зависимости также вызываются FastAPI (как и ваши функции обработки пути), применяются те же правила при определении ваших функций.
Вы можете использовать async def
или обычное def
.
И вы можете объявлять зависимости с async def
внутри обычных функций обработки пути def
, или зависимости def
внутри функций обработки пути async def
и т. д.
Это не важно. FastAPI знает, что делать.
/// note | Примечание
Если вы не уверены, посмотрите раздел Async: "In a hurry?"{.internal-link target=_blank} о async
и await
в документации.
///
Интеграция с OpenAPI
Все объявления запросов, проверки и требования ваших зависимостей (и подзависимостей) будут интегрированы в ту же схему OpenAPI.
Поэтому в интерактивной документации будет вся информация и из этих зависимостей:

Простое использование
Если посмотреть, функции обработки пути объявляются для использования всякий раз, когда путь и операция совпадают, и тогда FastAPI заботится о вызове функции с корректными параметрами, извлекая данные из запроса.
На самом деле все (или большинство) веб-фреймворков работают таким же образом.
Вы никогда не вызываете эти функции напрямую. Их вызывает ваш фреймворк (в нашем случае FastAPI).
С системой Dependency Injection вы также можете сообщить FastAPI, что ваша функция обработки пути «зависит» от чего-то, что должно быть выполнено перед вашей функцией обработки пути, и FastAPI позаботится о его выполнении и «инъекции» результатов.
Другие распространённые термины для описания той же идеи «dependency injection»:
- ресурсы
- провайдеры
- сервисы
- внедряемые зависимости
- компоненты
Плагины FastAPI
Интеграции и «плагины» могут быть построены с использованием системы Dependency Injection. Но на самом деле нет необходимости создавать «плагины», так как, используя зависимости, можно объявить бесконечное количество интеграций и взаимодействий, которые становятся доступными вашим функциям обработки пути.
И зависимости можно создавать очень простым и интуитивным способом, который позволяет просто импортировать нужные пакеты Python и интегрировать их с вашими API-функциями в пару строк кода, буквально.
Вы увидите примеры этого в следующих главах о реляционных и NoSQL базах данных, безопасности и т.д.
Совместимость с FastAPI
Простота системы Dependency Injection делает FastAPI совместимым с:
- всеми реляционными базами данных
- NoSQL базами данных
- внешними пакетами
- внешними API
- системами аутентификации и авторизации
- системами мониторинга использования API
- системами инъекции данных в ответы
- и т.д.
Просто и мощно
Хотя иерархическая система dependency injection очень проста для определения и использования, она по-прежнему очень мощная.
Вы можете определять зависимости, которые, в свою очередь, могут иметь собственные зависимости.
В итоге строится иерархическое дерево зависимостей, и система Dependency Injection берёт на себя решение всех этих зависимостей (и их подзависимостей) и предоставляет (инъектирует) результаты на каждом шаге.
Например, у вас есть 4 API-эндпоинта (операции пути):
/items/public/
/items/private/
/users/{user_id}/activate
/items/pro/
тогда вы можете добавить разные требования к правам для каждого из них только с помощью зависимостей и подзависимостей:
graph TB
current_user(["current_user"])
active_user(["active_user"])
admin_user(["admin_user"])
paying_user(["paying_user"])
public["/items/public/"]
private["/items/private/"]
activate_user["/users/{user_id}/activate"]
pro_items["/items/pro/"]
current_user --> active_user
active_user --> admin_user
active_user --> paying_user
current_user --> public
active_user --> private
admin_user --> activate_user
paying_user --> pro_items
Интегрировано с OpenAPI
Все эти зависимости, объявляя свои требования, также добавляют параметры, проверки и т.д. к вашим операциям пути.
FastAPI позаботится о добавлении всего этого в схему OpenAPI, чтобы это отображалось в системах интерактивной документации.