Какой принцип SOLID реализует механизм зависимостей (Depends) в FastAPI

Ответ

Механизм Depends в FastAPI является реализацией принципа инверсии зависимостей (Dependency Inversion Principle, D) из SOLID.

Этот принцип утверждает, что модули высокого уровня не должны зависеть от модулей низкого уровня. И те, и другие должны зависеть от абстракций.

В FastAPI Depends работает как система внедрения зависимостей (Dependency Injection). Это позволяет:

  • Декларировать зависимости прямо в сигнатуре функции-обработчика.
  • Отделить бизнес-логику эндпоинта от логики получения зависимостей (например, сессии БД, аутентификации пользователя).
  • Упростить тестирование, так как зависимости можно легко подменить (mock).

Пример:

from fastapi import Depends, FastAPI

app = FastAPI()

# Абстракция: функция, предоставляющая зависимость (например, сессию БД)
def get_db_session():
    db_session = "fake_db_session"
    try:
        yield db_session
    finally:
        print("DB session closed")

# Модуль высокого уровня (эндпоинт)
@app.get("/items/")
async def read_items(db = Depends(get_db_session)):
    # Эндпоинт не создает сессию сам, а получает ее через Depends.
    # Он зависит от абстракции `get_db_session`, а не от конкретной реализации.
    return {"message": f"Items read from {db}"}

Ответ 18+ 🔞

А, ну это же про тот самый принцип, который все всуе поминают, а на деле нихуя не понимают! Слушай сюда, сейчас разжую.

Вот есть у тебя, допустим, роутер, который должен с базой данных работать. По-простому, по-деревенски, ты бы прямо в нём и создавал подключение, да? Ну типа db = connect_to_db(). И вроде бы всё работает, но потом оказывается, что ты, блядь, прирос к этой конкретной базе как репейник к штанам. Захотел протестировать — хуй тебе, а не тесты, потому что везде эта конкретная база зашита. Это и есть нарушение принципа инверсии зависимостей, ёпта!

А суть-то в чём? Модули высокого уровня (твой роутер, твоя бизнес-логика) не должны зависеть от модулей низкого уровня (конкретная функция подключения к PostgreSQL). Они должны зависеть от абстракций! То есть твой роутер должен говорить: «Дайте мне какую-нибудь штуку, через которую я могу с базой общаться», а не «Дайте мне именно эту сессию от этого драйвера».

И вот тут FastAPI подъезжает на белом коне с механизмом Depends. Это, по сути, система внедрения зависимостей, которая делает тебя нереально крутым архитектором, даже если ты вчера только из деревни приехал.

Что она позволяет, блядь?

  • Объявлять зависимости прямо в аргументах хэндлера. Красиво, наглядно, сразу видно, что этому эндпоинту нужно для работы.
  • Отделить всю эту техническую муть вроде открытия сессий, проверки токенов и прочей ерунды от самой сути — твоей бизнес-логики. Эндпоинт занимается своим делом, а не возится с низкоуровневым хозяйством.
  • Тестировать всё это безболезненно. Захотел — подсунул в тестах заглушку вместо реальной базы, и поехали. Никаких костылей, всё элегантно, как у настоящих джентльменов.

Смотри, как это выглядит в коде, тут всё просто, как три копейки:

from fastapi import Depends, FastAPI

app = FastAPI()

# Вот это наша абстракция, наша «фабрика зависимости».
# Она не делает ничего умного, просто говорит: «Эй, кто бы меня ни вызвал, вот тебе сессия!»
def get_db_session():
    db_session = "fake_db_session"  # Тут, понятное дело, будет реальное подключение
    try:
        yield db_session  # Отдаём сессию тому, кто попросил
    finally:
        print("DB session closed")  # И гарантированно прибираем за собой, даже если всё пошло по пизде

# А вот это наш модуль высокого уровня — эндпоинт.
# Он не парится, КАК получить сессию. Он просто говорит: «Мне нужна сессия».
# А система сама её подсунет через `Depends`.
@app.get("/items/")
async def read_items(db = Depends(get_db_session)):
    # И вот он, красавец, работает с базой, даже не зная, откуда она взялась.
    return {"message": f"Items read from {db}"}

Вот и вся магия, ёбана! Твой код становится чище, гибче и перестаёт быть монолитной глыбой, которую страшно трогать. А главное — ты начинаешь чувствовать себя не просто кодёром, а архитектором, блядь! Ну, почти.