Какой архитектурный подход используется в FastAPI?

Ответ

FastAPI не навязывает строгий архитектурный паттерн, но его дизайн естественным образом способствует организации кода по принципам, схожим с Model-View-Controller (MVC), с сильным акцентом на Dependency Injection (DI).

Основные компоненты можно соотнести так:

  • Модели (Model): Определяются с помощью Pydantic для валидации и сериализации данных (входящих запросов и исходящих ответов). Для работы с базой данных используются ORM (например, SQLAlchemy, Tortoise ORM), которые также представляют собой модели.
  • Представления (View): В FastAPI это функции-обработчики маршрутов (path operation functions), декорированные @app.get, @app.post и т.д. Они отвечают за обработку HTTP-запросов, вызов бизнес-логики и формирование HTTP-ответов.
  • Контроллеры (Controller): Бизнес-логика, которая может быть инкапсулирована в отдельные функции или классы и вызываться из функций-обработчиков. FastAPI поощряет вынесение сложной логики в отдельные модули для чистоты и тестируемости.

Dependency Injection (DI) является ключевой особенностью FastAPI. Она позволяет:

  • Управлять зависимостями: Легко внедрять общие ресурсы (например, сессии базы данных, аутентификационные токены, конфигурацию) в функции-обработчики.
  • Повысить тестируемость: Зависимости можно легко мокать (mock) при тестировании.
  • Улучшить переиспользование кода: Общая логика может быть вынесена в переиспользуемые зависимости.

Пример:

from fastapi import FastAPI, Depends
from pydantic import BaseModel

app = FastAPI()

# Model (Pydantic)
class Item(BaseModel):
    name: str
    price: float

# Dependency (DI) - имитация получения ресурса (например, сессии БД)
def get_db():
    """Имитирует получение сессии базы данных."""
    return "fake_db_session_123"

# View/Controller (Path Operation Function)
@app.post("/items/")
def create_item(item: Item, db: str = Depends(get_db)):
    """
    Создает новый товар, используя внедренную зависимость.
    """
    # Здесь могла бы быть бизнес-логика сохранения item в БД
    return {"item": item, "db_session": db}

Такой подход делает код модульным, легко тестируемым, расширяемым и способствует созданию чистых API.

Ответ 18+ 🔞

А, слушай, смотри, вот этот FastAPI, он вроде как не стоит над душой с каким-то одним правильным архитектурным паттерном, но сам по себе так хитрожопо сделан, что код сам собой встаёт по полочкам, почти как в MVC, понимаешь? И вся его магия крутится вокруг Dependency Injection (DI), это его конёк, блядь.

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

  • Модели (Model): Ну, это понятно. Pydantic'ом пишешь, как данные должны выглядеть — что прилетает в запросе, что улетает в ответе. А если с базой работать, то ORM типа SQLAlchemy — это тоже по сути модели, ёпта. Всё для валидации и сериализации, чтоб не прилетело какого-нибудь пиздеца вместо числа.
  • Представления (View): А это, сука, те самые функции, которые ты декорируешь @app.get, @app.post. Они как раз на передовой — ловят HTTP-запросы, вызывают нужную бизнес-логику и отдают ответ. Всё как у людей.
  • Контроллеры (Controller): А вот это уже вся твоя хитрая бизнес-логика, которую ты из этих функций-обработчиков вызываешь. FastAPI прямо-таки поощряет выносить её в отдельные модули, чтоб не превращать обработчик в помойку длиной в километр. Чистота, тестируемость, всё дела.

А теперь, внимание, главная фишка — Dependency Injection (DI). Это не просто модное словечко, это реально удобная хуйня, которая позволяет:

  • Зависимости управлять: Нужна сессия базы данных? Токен аутентификации? Конфиг? Всё это можно запихнуть как зависимость, и она автоматом подтянется туда, где нужна. Не надо вручную тащить через все функции.
  • Тестировать проще: Зависимости можно подменить на моки, и не надо городить огород, чтобы протестировать один маленький кусочек.
  • Код переиспользовать: Общую логику (типа проверки прав) выносишь в одну зависимость и юзаешь её в десятке эндпоинтов. Красота, блядь!

Вот смотри, наглядный пример, чтоб совсем ясно стало:

from fastapi import FastAPI, Depends
from pydantic import BaseModel

app = FastAPI()

# Модель (Pydantic) - вот как должен выглядеть товар
class Item(BaseModel):
    name: str
    price: float

# Зависимость (DI) - типа получаем сессию базы (тут фейковая, для примера)
def get_db():
    """Прикидывается, что отдаёт сессию базы данных."""
    return "fake_db_session_123"

# Представление/Контроллер (Функция-обработчик маршрута)
@app.post("/items/")
def create_item(item: Item, db: str = Depends(get_db)):
    """
    Создаёт новый товар, используя внедрённую зависимость (сессию БД).
    """
    # Тут могла бы быть твоя бизнес-логика, типа сохранить item в БД через эту db
    return {"item": item, "db_session": db}

Вот и вся магия. Такой подход делает код не абы каким, а модульным, тестируемым, расширяемым и в целом охуенно чистым. Не надо изобретать велосипед, всё уже продумано.