Тема 6 из 6

API списка задач

Соберём всё вместе и доведём API списка задач до вида, в котором его не стыдно отдать фронтенду или мобильному приложению.

Параметр из списка значений

from typing import Literal


@app.get("/todos")
def list_todos(sort: Literal["title", "priority"] = "title"):
    ...

Literal (или класс-перечисление Enum) разрешает только перечисленные значения: остальные получат 422. В /docs такой параметр показывается выпадающим списком.

Сортировка и сводки

Сложную сортировку задают ключом-кортежем: key=lambda t: (-t["priority"], t["title"].lower()) — сначала по убыванию приоритета, при равенстве — по названию. Для сводок помогают sum(...), // (округление вниз) и словари-счётчики. Не забывайте о пустых данных: done * 100 // total упадёт, если задач нет.

В JSON ключи словаря всегда строки, поэтому {2: 1} клиент получит как {"2": 1}.

APIRouter

В большом проекте маршруты раскладывают по файлам:

# todos.py
from fastapi import APIRouter

router = APIRouter(prefix="/todos", tags=["Задачи"])


@router.get("/")            # → /todos/
def list_todos(): ...


@router.get("/{tid}")       # → /todos/{tid}
def get_todo(tid: int): ...
# main.py
from fastapi import FastAPI
from todos import router

app = FastAPI()
app.include_router(router)
  • адреса внутри роутера пишутся без префикса;
  • подключают роутер один раз, обычно в главном файле после импорта модуля с маршрутами;
  • tags группируют маршруты в /docs.

async def

@app.get("/weather")
async def weather():
    async with httpx.AsyncClient() as client:
        r = await client.get("https://api.example.com/weather")
    return r.json()

Маршрут можно объявить через async def, если внутри есть await — асинхронный запрос к другому API или базе. Пока один запрос ждёт ответа, сервер обслуживает другие. Обычные def FastAPI запускает в отдельных потоках, так что медленный, но синхронный код лучше оставлять в обычных функциях.

Что дальше

Данные хранят в базе: с FastAPI часто используют SQLAlchemy или SQLModel (от автора FastAPI). Готовое приложение запускают командой uvicorn main:app --host 0.0.0.0 --port 8000 на сервере или в Docker.

Итог

  • Literal[...] — параметр из списка значений;
  • сортировка ключом-кортежем, сводки с защитой от пустых данных;
  • APIRouter(prefix=…) и app.include_router(router);
  • async def — когда внутри есть await.