APIСтандартизация
тема 1
Открыть слайдами →

54FastAPI строит OpenAPI из Python-кода

FastAPI читает маршруты, аннотации типов и модели Pydantic и сам собирает документ OpenAPI.

АдресЧто открывается
/docsSwagger UI
/redocReDoc
/openapi.jsonOpenAPI schema

Эти адреса есть у приложения по умолчанию. Схема строится при первом обращении и совпадает с кодом, потому что получена из него.

  1. Python code
  2. FastAPI
  3. openapi.json
  4. Swagger UI · ReDoc

55Открываем интерактивную документацию

Запускаем учебный проект и открываем Swagger UI.

терминал, папка api-standard-template
pip install -r requirements.txt
uvicorn app.main:app --reload

В браузере перейти:

http://127.0.0.1:8000/docs
  1. Найти группу Tickets.
  2. Раскрыть GET /api/v1/tickets.
  3. Сверить название API и версию в шапке.

Кадры этой части сняты на версии 1.0.0. Заголовки, которые появились в 1.1.0, разобраны в части 13.

Swagger UI · /docsСКРИНШОТ · 15.09.2026
Шапка Service Desk API с версией 1.0.0 и отметкой OAS 3.1, группа Tickets, раскрытая операция GET /api/v1/tickets. Клик — увеличить.

56Swagger UI не является источником контракта

Swagger UI только отображает документ. Сам контракт — JSON по адресу /openapi.json.

http://127.0.0.1:8000/openapi.json
  1. Найти "openapi": "3.1.0".
  2. Найти "info" с названием и версией.
  3. Найти "paths" со всеми адресами.

Swagger UI является визуальным представлением этого документа.

Если JSON отображается одной строкой, включите в Chrome флажок «Автоформатировать» над текстом.

Chrome · /openapi.jsonСКРИНШОТ · 15.09.2026
OpenAPI schema учебного проекта с автоформатированием: выделены "openapi": "3.1.0", "info" и "paths". Клик — увеличить.

57Один OpenAPI — разные интерфейсы документации

Открываем тот же контракт в другом интерфейсе и сравниваем.

http://127.0.0.1:8000/redoc

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

Обе системы получают данные из одного API contract. Разница только в способе отображения.

Если /redoc пустой. FastAPI 0.115 подключает скрипт ReDoc по тегу redoc@next, а CDN по этому тегу больше не отдаёт файл. В учебном проекте версия закреплена явно: redoc@2.5.4 в app/main.py.

ReDoc · /redocСКРИНШОТ · 15.09.2026
ReDoc с Service Desk API: левая навигация, описание операции «Получить список обращений», примеры ответов 200 и 422. Клик — увеличить.

58Документируем API на уровне приложения

Метаданные задаются параметрами конструктора FastAPI в файле app/main.py.

app/main.py
app = FastAPI(
    title="Service Desk API",
    version="1.0.0",
    summary="Учебный стандартизированный REST API",
    description=API_DESCRIPTION,
    contact={
        "name": "API Team",
        "email": "api-team@example.edu",
    },
)

После сохранения файла сервер с флагом --reload перезапустится сам. Обновите /docs.

Swagger UI · шапкаСКРИНШОТ · 15.09.2026
Каждый параметр конструктора виден в Swagger UI: title, version, summary, description и контакт API Team. Клик — увеличить.

59Endpoint должен объяснять своё назначение

Аргументы декоратора маршрута становятся полями operation в OpenAPI.

app/api/v1/endpoints/tickets.py
@router.get(
    "",
    response_model=TicketPage,
    summary="Получить список обращений",
    description="Возвращает страницу обращений...",
    operation_id="listTickets",
)
def list_tickets(...) -> TicketPage:
    ...
АргументПоле OpenAPI
response_modelschema ответа 200
summarysummary
operation_idoperationId
Swagger UI · listTicketsСКРИНШОТ · 15.09.2026
Раскрытая операция: summary рядом с путём, описание, параметры и ответ 200 со схемой TicketPage. Клик — увеличить.

60Одной модели недостаточно

Создание, изменение и ответ описываются разными схемами, потому что содержат разные поля.

app/schemas.py (сокращено)
class TicketCreate(BaseModel):
    model_config = ConfigDict(extra="forbid")
    title: str = Field(min_length=3, max_length=120)
    description: str = ""

class TicketUpdate(BaseModel):
    title: str | None = None
    description: str | None = None
    status: TicketStatus | None = None

class Ticket(BaseModel):
    id: UUID
    title: str
    description: str
    status: TicketStatus
    created_at: datetime
    updated_at: datetime
ГдеСхема
POST requestTicketCreate
PATCH requestTicketUpdate
ResponseTicket
СписокTicketPage

Клиент не должен передавать id при создании: его формирует сервер. Благодаря extra="forbid" запрос с лишним полем id получит 422, это проверяет тест test_client_cannot_send_id.

Кадр крупным планом