Ответ
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}
Вот и вся магия. Такой подход делает код не абы каким, а модульным, тестируемым, расширяемым и в целом охуенно чистым. Не надо изобретать велосипед, всё уже продумано.