Ответ
Создание проекта на FastAPI следует структурировать вокруг его ключевых возможностей: моделей данных Pydantic, инъекции зависимостей и асинхронности. Ниже приведены основные шаги и лучшие практики.
1. Валидация данных с помощью Pydantic
Всегда определяйте модели для входящих и исходящих данных. Это обеспечивает валидацию, преобразование типов и автоматическую генерацию документации.
from pydantic import BaseModel, Field
class ItemCreate(BaseModel):
name: str = Field(..., min_length=3, description="Название товара")
price: float = Field(..., gt=0, description="Цена должна быть положительной")
class ItemResponse(BaseModel):
id: int
name: str
2. Структурирование проекта с помощью APIRouter
Для проектов сложнее одного файла используйте APIRouter для разделения эндпоинтов на логические модули. Это улучшает читаемость и поддержку кода.
# /routers/items.py
from fastapi import APIRouter
router = APIRouter(
prefix="/items",
tags=["items"],
)
@router.get("/")
async def read_items():
return [{"name": "Item 1"}]
# /main.py
from fastapi import FastAPI
from .routers import items
app = FastAPI()
app.include_router(items.router)
3. Использование инъекции зависимостей (Depends)
Выносите повторяющуюся логику (например, подключение к БД, аутентификацию пользователя) в функции-зависимости. Это соответствует принципу DRY (Don't Repeat Yourself) и упрощает тестирование.
from fastapi import Depends, FastAPI
async def get_db_session():
# Логика получения сессии БД
db = ...
try:
yield db
finally:
db.close()
@app.get("/users/me")
async def read_current_user(db: Session = Depends(get_db_session)):
# работа с db
return {"user": "current"}
4. Асинхронная работа с базой данных и другими I/O
Используйте асинхронные драйверы для баз данных (asyncpg для PostgreSQL, motor для MongoDB) и HTTP-клиенты (httpx). Это позволяет вашему приложению эффективно обрабатывать большое количество одновременных запросов, не блокируя основной поток выполнения.
5. Управление конфигурацией
Не храните конфигурационные данные (ключи API, данные для подключения к БД) в коде. Используйте переменные окружения и библиотеки, такие как pydantic-settings, для их безопасной загрузки.
6. Централизованная обработка ошибок
Используйте декоратор @app.exception_handler() для создания кастомных обработчиков исключений. Это позволяет возвращать клиенту осмысленные и стандартизированные ответы об ошибках.
Ответ 18+ 🔞
А, слушай, смотри, вот тебе, блядь, как на FastAPI проект делать, чтобы не было потом мучительно больно, как говорится. В рот меня чих-пых, народ же любит всё в одну кучу свалить, а потом охуевает, почему ничего не работает.
Первое, и главное — Pydantic, твоя броня от долбоёбов.
Всё, что приходит и уходит, оборачивай в эти модели. Не просто request.json() и вперёд, а то потом какой-нибудь умник пришлёт цену в виде строки "десять рублей", и вся твоя логика накрывается медным тазом. Смотри, как надо:
from pydantic import BaseModel, Field
class ItemCreate(BaseModel):
name: str = Field(..., min_length=3, description="Название товара")
price: float = Field(..., gt=0, description="Цена должна быть положительной")
class ItemResponse(BaseModel):
id: int
name: str
Вот видишь? gt=0 — это чтобы какой-нибудь хитрожопый не прислал цену -100, а потом орал, что у него на балансе овердохуища денег. FastAPI сам проверит, отфутболит и в документации красиво покажет. Ёперный театр, красота!
Второе — не лепи всё в один файл main.py на тысячу строк.
Это ж пиздец какой-то получается, найти что-то — всё равно что иголку в стоге сена искать. Дроби на роутеры!
# /routers/items.py
from fastapi import APIRouter
router = APIRouter(
prefix="/items",
tags=["items"], # И в документации всё аккуратно по полочкам
)
@router.get("/")
async def read_items():
return [{"name": "Item 1"}]
# /main.py
from fastapi import FastAPI
from .routers import items
app = FastAPI()
app.include_router(items.router)
Вот так, блядь. Один файл — товары, другой — пользователи, третий — заказы. Всё логично, всё понятно. А то смотришь на монолит — и волнение ебать, терпения ноль ебать.
Третье — инъекция зависимостей, она же Depends.
Это не какая-то магия, а просто способ не повторять один и тот же код в каждом втором эндпоинте. Подключение к базе, проверка прав — выноси в отдельную функцию.
from fastapi import Depends, FastAPI
async def get_db_session():
# Логика получения сессии БД
db = ...
try:
yield db # Отдал сессию, работай
finally:
db.close() # Всё сделал — прибрал за собой, не как свинья
@app.get("/users/me")
async def read_current_user(db: Session = Depends(get_db_session)):
# работа с db
return {"user": "current"}
Смотри, какая прелесть! Хочешь протестировать — подменил get_db_session на заглушку, и всё, ни одна реальная база не пострадала. DRY, блядь, в действии — Don't Repeat Yourself, а не «суши себя», как некоторые думают.
Четвёртое — асинхронность, но без фанатизма.
Если твоё приложение только считает числа в памяти — асинхронность тебе, как собаке пятая нога. Но если есть I/O — база, внешние API, файлы — тогда да, async/await в руки. Только смотри, драйвер базы должен быть асинхронный (asyncpg, motor), а то будет как в том анекдоте: «ждун». Блокирующая операция в асинхронном потоке — и всё, приехали, производительность хуй с горы.
Пятое — конфиги, ёбта, не в коде!
Никаких DATABASE_URL = "postgresql://admin:12345@localhost/mydb" прямо в скрипте! Это же пиздец, какой уровень распиздяйства. Выноси в переменные окружения, используй pydantic-settings. А то выложишь на гитхаб, а там уже тебе на сервер лезут, потому что пароль от базы как на ладони. Сам от себя охуеешь потом.
Шестое — ошибки.
Нельзя, чтобы приложение падало с пятисотой ошибкой, а клиент получал просто Internal Server Error и ни хуя не понял. Обрабатывай исключения централизованно!
from fastapi import Request
from fastapi.responses import JSONResponse
@app.exception_handler(ValueError)
async def value_error_handler(request: Request, exc: ValueError):
return JSONResponse(
status_code=400,
content={"message": f"Некорректные данные, дружок: {exc}"},
)
Вот так, по-человечески объяснил, в чём проблема. А не как обычно: «ошибка сервера, иди нахуй».
Короче, суть в чём: FastAPI — инструмент мощный, но если им как лопатой махать, можно и по лбу получить. Структурируй, валидируй, разделяй ответственность. И будет тебе счастье, а не техдолг, который потом разгребать — одни ебушки-воробушки.