Внедрение зависимостей в FastAPI
FastAPI предоставляет мощную и лаконичную систему внедрения зависимостей.
Внедрение зависимостей — это шаблон проектирования, который позволяет вынести общую логику (например, подключения к базе данных, аутентификацию, проверку параметров и т. д.) в повторно используемые компоненты, а затем использовать их по мере необходимости в маршрутах.

Что такое внедрение зависимостей
Проще говоря,Зависимость— это по сути функция, которая может использовать те же параметры, что и функции операций пути (параметры запроса, параметры пути, тело запроса и т. д.). FastAPI автоматически вызовет функцию зависимости перед выполнением функции маршрута и передаст её возвращаемое значение функции маршрута.
Пример
from fastapi import Depends, FastAPI
app = FastAPI()
# 1. Определите функцию зависимости
def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
# 2. Использование зависимостей в маршрутах
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
# commons получает возвращаемое значение функции зависимости
return commons
@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
# Несколько маршрутов могут использовать одну и ту же зависимость
return commons
Пояснение к коду:
| Часть | Описание |
|---|---|
common_parameters | Функции зависимостей, обрабатывающие общие параметры запроса |
Depends(common_parameters) | Объявите параметрыcommonsЗначение поступает из функции зависимости |
commons: dict | Получает словарь, возвращаемый функцией зависимости |
Функции зависимостей и функции операций пути используют один и тот же стиль объявления параметров, и FastAPI автоматически разрешает параметры функции зависимости. Это означает, что функции зависимостей также могут использовать параметры запроса, параметры пути, тело запроса и т. д.
Поток выполнения зависимостей
Когда приходит запрос, порядок обработки FastAPI:
- Определить функции маршрута и их зависимости
- Выполнить функции зависимостей (в порядке зависимостей)
- Передать возвращаемое значение функции зависимости в функцию маршрута.
- Выполнить функцию маршрута
Класс как зависимость
Помимо функций, вы также можете использовать классы в качестве зависимостей:
Пример
from fastapi import Depends, FastAPI
app = FastAPI()
# Объявление зависимостей с помощью классов
class CommonQueryParams:
def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit
# Использовать класс в качестве зависимости
@app.get("/items/")
async def read_items(commons: Annotated[CommonQueryParams, Depends()]):
return {"q": commons.q, "skip": commons.skip, "limit": commons.limit}
КогдаDepends()Когда параметр не передан, FastAPI автоматически использует аннотацию типа параметра (CommonQueryParams) в качестве зависимости.
подзависимость
Зависимости могут иметь свои собственные зависимости, образуя цепочку зависимостей:
Пример
from fastapi import Depends, FastAPI
app = FastAPI()
# Функции зависимостей
def query_extractor(q: str | None = None):
return q
# Подзависимость: зависит от query_extractor.
def query_checker(q: str = Depends(query_extractor)):
if q == "admin":
# Подзависимости можно проверять
return q + " (checked)"
return q
# Маршруты используют подзависимости
@app.get("/items/")
async def read_items(q: str = Depends(query_checker)):
return {"q": q}
Поток выполнения:query_extractor -> query_checker-> функция маршрута
Использование зависимостей в декораторах
Иногда вам нужны только побочные эффекты зависимости (например, проверки разрешений), а не её возвращаемое значение. В декоратореdependenciesОбъявлено в параметрах:
Пример
app = FastAPI()
# Зависимость: проверка API-ключа
async def verify_api_key(x_api_key: str = Header()):
if x_api_key != "secret-key":
raise HTTPException(status_code=400, detail="X-API-Key invalid")
# Использование зависимости в декораторе, возвращаемое значение не требуется
@app.get("/items/", dependencies=[Depends(verify_api_key)])
async def read_items():
return [{"item": "Foo"}]
# Применить зависимость ко всей группе маршрутов
@app.get("/users/", dependencies=[Depends(verify_api_key)])
async def read_users():
return [{"user": "Bar"}]
Глобальные зависимости
Вы можетеFastAPIОбъявите глобальные зависимости на экземпляре, действующие для всех маршрутов:
Пример
async def verify_token(x_token: str = Header()):
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="Неверный заголовок X-Token")
# Глобальная зависимость: все маршруты должны проходить проверку токена
app = FastAPI(dependencies=[Depends(verify_token)])
@app.get("/items/")
async def read_items():
return [{"item": "Foo"}]
@app.get("/users/")
async def read_users():
return [{"user": "Bar"}]
Зависимости с использованием yield
Когда зависимость должна выполнить операции очистки (например, закрытие соединений с базой данных), используйтеyield:
Пример
from fastapi import Depends, FastAPI
app = FastAPI()
# Зависимости, использующие yield: создайте соединение до запроса и закройте его после запроса.
def get_db():
db = "database_connection" # Имитация создания соединения с базой данных
try:
yield db # Предоставить подключение к базе данных во время обработки запроса
finally:
print("Close database connection") # Освободить ресурсы после завершения запроса
@app.get("/items/")
async def read_items(db: str = Depends(get_db)):
return {"db": db}
Поток выполнения:
- При поступлении запроса выполняется
yieldКод до этого, создающий подключение к базе данных yieldПередайте подключение в функцию маршрута- После завершения функции маршрута выполняется
finallyКод очистки в блоке
yieldЗависимости идеально подходят для управления ресурсами, требующими очистки, например подключениями к базе данных и файловыми дескрипторами. Код очистки выполнится независимо от того, выбросит ли функция маршрута исключение.
Итог
- Внедрение зависимостей выделяет общую логику в переиспользуемые функции или классы.
- Использование
Depends()Объявите зависимости в параметрах функции маршрута - Зависимости могут быть вложенными, образуя цепочки зависимостей
- декоратора
dependenciesПараметры, используемые для зависимостей, которым не нужны возвращаемые значения - Использование
yieldЗависимости поддерживают очистку ресурсов - Глобальные зависимости применяются ко всем маршрутам