Что такое Dependency Injection в FastAPI?

Ответ

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

Почему это важно? DI значительно упрощает архитектуру приложения, делая код более модульным, тестируемым и поддерживаемым. Он позволяет избежать жесткой привязки компонентов и легко заменять их (например, для тестирования или использования разных конфигураций).

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

Пример с управлением ресурсами (сессия БД):

from fastapi import FastAPI, Depends, HTTPException, status
from typing import Generator

app = FastAPI()

# Имитация подключения к базе данных
def get_db_connection() -> Generator[str, None, None]:
    db_session = "Connected to DB"
    try:
        print(f"[DB] Открываем соединение: {db_session}")
        yield db_session  # Передаем сессию в обработчик маршрута
    finally:
        print(f"[DB] Закрываем соединение: {db_session}")
        # Здесь обычно происходит закрытие соединения с БД

@app.get("/items/")
def read_items(db: str = Depends(get_db_connection)):
    """Получение списка элементов, используя зависимость от БД."""
    if not db:
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="DB connection failed")
    return {"message": f"Используем: {db} для получения элементов"}

@app.get("/users/")
def read_users(db: str = Depends(get_db_connection)):
    """Получение списка пользователей, используя ту же зависимость."""
    return {"message": f"Используем: {db} для получения пользователей"}

Ключевые преимущества:

  • Переиспользование кода: Одна зависимость может быть использована в множестве маршрутов.
  • Тестируемость: Легко подменять реальные зависимости "моками" в тестах, изолируя тестируемый код.
  • Управление ресурсами: Генераторы с yield и try...finally идеально подходят для управления жизненным циклом ресурсов (открытие/закрытие соединений, транзакций).
  • Чистота кода: Логика обработчика маршрута остается сфокусированной на своей основной задаче, а не на получении зависимостей.
  • Каскадные зависимости: Зависимости могут зависеть от других зависимостей, создавая цепочки.