Какой ключевой паттерн проектирования отличает FastAPI от других Python-фреймворков?

Ответ

Ключевой паттерн, который выделяет FastAPI, — это Внедрение зависимостей (Dependency Injection, DI).

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

Пример: зависимость для получения сессии БД

from fastapi import FastAPI, Depends
from typing import Generator

app = FastAPI()

# Зависимость: генератор, который создает и закрывает сессию
def get_db_session() -> Generator:
    db = "database_session_started"
    try:
        yield db
    finally:
        # Этот код выполнится после отправки ответа
        print("database_session_closed")

@app.get("/items/")
async def read_items(db_session: str = Depends(get_db_session)):
    # Логика, использующая сессию БД
    return {"message": f"Data fetched using {db_session}"}

Почему это важно:

  • Тестируемость: Зависимости (get_db_session) легко подменить моками (mocks) в тестах.
  • Переиспользование кода: Одна и та же зависимость (например, проверка токена) может использоваться в десятках эндпоинтов.
  • Разделение ответственности (SoC): Логика получения зависимости отделена от бизнес-логики эндпоинта.

Ответ 18+ 🔞

Слушай, смотри, вот этот FastAPI, он же на одной главной фишке и держится, как слон на трёх ногах — на Внедрении зависимостей, или, по-пацански, Dependency Injection (DI).

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

Вот смотри, как он сессию к базе прикручивает:

from fastapi import FastAPI, Depends
from typing import Generator

app = FastAPI()

# Вот эта функция — наша зависимость. Генератор, сука!
def get_db_session() -> Generator:
    db = "database_session_started"
    try:
        yield db  # Отдаём сессию тому, кто попросил
    finally:
        # А это выполнится уже после того, как ответ улетел, красота!
        print("database_session_closed")

@app.get("/items/")
async def read_items(db_session: str = Depends(get_db_session)):
    # И вот она, сессия, уже здесь! Бери и пользуйся.
    return {"message": f"Data fetched using {db_session}"}

И в чём, собственно, охуенность, спросишь ты?

  • Тесты, ёпта! Захотел потестить — подменил эту get_db_session на какую-нибудь заглушку, и всё, ни одна реальная база не пострадала. Красота, а не жизнь.
  • Не повторяйся, мудак! Написал один раз функцию, которая проверяет, что у юзера есть права, и втыкай её в сотню эндпоинтов через Depends. Один раз написал — везде работает, волнение ебать.
  • Всё по полочкам. Логика «как достать сессию» живёт отдельно от логики «что с этой сессией делать». Голова не болит, код не воняет. Просто праздник какой-то, в рот меня чих-пых!