Модуль 8 · Практика

Справочник «Стандартизация HTTP API» · модуль 8 · Практика

Глава 8.1

8.1

Свой API
по правилам

В предыдущих модулях разбирался готовый контракт. Практическая работа состоит в том, чтобы составить свой: выбрать предметную область, описать операции, реализовать их и настроить проверки, которые не дадут контракту разойтись с кодом. Работа выполняется по шагам, каждый шаг опирается на отдельную главу справочника.

Категория
Практика
Уровень
Итоговый
Связанные главы
весь справочник · 8.2 Отчёт и критерии
Что получится
Репозиторий с работающим API, описанием, проверками и документацией

§1Что нужно сделать

Собрать репозиторий со своим HTTP API: не копию учебного, а свой — по своей предметной области, но по тем же правилам.

Часть работыМинимумГде разбиралось
Ресурс и адресаОдна коллекция и её элементыглава 1.3
ОперацииПять: список, создание, чтение, изменение, удалениеглавы 2.2, 2.3
Описание OpenAPIВыгружено в файл, в репозиторииглавы 3.1–3.3
ОшибкиProblem Details, не меньше четырёх кодовглава 4.1
ЗаголовкиX-Request-Id обязательно, дальше по выборуглава 4.3
ВерсияПуть /api/v1 и info.version по SemVerглава 5.1
СтандартСвой API_STYLE_GUIDE.md с уровнями требованийглава 6.1
ПроверкиТесты и линтер, запускаются в сборкеглавы 6.2–6.4
ДокументыREADME, CHANGELOG, один ADRглавы 5.4, 7.1

Учебный проект api-standard-template — образец, а не заготовка для копирования. Обращаться к нему при выполнении работы следует, но переносить целиком нельзя: предметная область другая, а вместе с ней другими будут ресурсы, поля и ошибки.

§2Шаг 1. Предметная область

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

Подходит

Заявки на оборудование, бронирование аудиторий, читательские формуляры, заказы в столовой, задачи в личном планировщике, записи в очередь к врачу.

Не подходит

«Соцсеть», «маркетплейс», «CRM» — слишком крупно: за занятие не получится ни описать, ни реализовать, ни проверить.

Проверьте выбор так: опишите, что происходит с одной записью от создания до удаления. Если описание не укладывается в несколько предложений, область слишком велика и её нужно сузить.

пример формулировки
Предметная область: бронирование аудиторий.
Сущность: бронь аудитории на дату и пару.
Состояния: requested → confirmed → cancelled.
Кто пользуется: староста (создаёт), диспетчер (подтверждает), все (читают).

§3Шаг 2. Ресурсы и адреса

Из описания области выделите ресурс и назовите адреса по правилам главы 1.3.

  1. Существительное во множественном числе для коллекции: /bookings, а не /booking и не /createBooking.
  2. Идентификатор в пути для элемента: /bookings/{booking_id}.
  3. Фильтры и пагинация — параметрами запроса: ?status=confirmed&limit=20&offset=0.
  4. Префикс версии впереди: /api/v1/bookings.
  5. Не глубже двух уровней вложенности. Нужен третий — скорее всего, там прячется отдельный ресурс.
получившийся список адресов
GET    /api/v1/bookings                 список, фильтр по status, пагинация
POST   /api/v1/bookings                 создать бронь
GET    /api/v1/bookings/{booking_id}    прочитать одну
PATCH  /api/v1/bookings/{booking_id}    изменить состояние или примечание
DELETE /api/v1/bookings/{booking_id}    отменить и удалить запись

§4Шаг 3. Операции и коды

Для каждой операции выпишите все исходы — успешные и нет. Удобно делать это таблицей: она потом прямо превращается в раздел responses описания.

ОперацияУспехОшибки
GET /bookings200422 — неверный limit
POST /bookings201 + Location401, 403, 422
GET /bookings/{id}200 + ETag404
PATCH /bookings/{id}200401, 403, 404, 412, 422
DELETE /bookings/{id}204401, 403, 404

Проверьте себя тремя вопросами из главы 2.3: возвращаете ли вы 201 именно при создании, 204 именно при удалении, и различаете ли 401 и 403. Это три наиболее частых упрощения, и все три проверяются в первую очередь.

§5Шаг 4. Схемы и ошибки

Опишите данные. Схем должно быть не меньше трёх — по главе 3.3:

schemas.py · заготовка
class BookingCreate(BaseModel):   # что присылает клиент
class BookingUpdate(BaseModel):   # изменение, все поля необязательны
class Booking(BaseModel):         # что возвращает сервер
class BookingPage(BaseModel):     # страница списка: items, total, limit, offset
ОбязательностьЧто клиент обязан прислать, а что нет. В модели создания — минимум обязательных полей.required
ОграниченияДлина строк, диапазоны чисел, перечисления состояний. Всё это попадёт в описание само.Field
Запрет лишнегоextra="forbid": клиент не присылает поля, которые формирует сервер.строгость
ПримерыХотя бы один осмысленный пример на схему — он окажется в Swagger UI.examples

Дальше — ошибки. Используйте формат Problem Details из главы 4.1 и не собирайте тело ошибки в каждом обработчике: один модуль, одна функция, три обработчика исключений.

Не забудьте про страницы видов проблем

Если поле type ведёт на адрес, по нему должна открываться страница. Публиковать её на GitHub Pages (глава 7.3) — плюс к работе; если публикации не будет, используйте about:blank, а не выдуманный домен.

§6Шаг 5. Реализация

Только теперь пишется код. Порядок такой же, как в учебном проекте.

структура репозитория

app/приложение: main.py, schemas.py, problems.py, storage.py, операции
openapi/выгруженное описание — файл в репозитории, а не только в памяти сервиса
scripts/export_openapi.pyвыгрузка описания и режим --check для сборки
tests/проверки описания и поведения
docs/стандарт, политика версий, ADR
.github/workflows/сборка контракта

Хранилище можно держать в памяти — база данных в этой работе не проверяется. Требуется другое: поведение должно совпадать с описанием, а состояние — сбрасываться между тестами.

проверка на ходу
uvicorn app.main:app --reload
# откройте http://127.0.0.1:8000/docs и выполните каждую операцию кнопкой Execute

§7Шаг 6. Проверки

Тесты описанияУ всех операций есть operationId, теги, описанные ответы; все пути с префиксом версии; ошибки — application/problem+json.глава 6.3
Тесты поведенияПо одному на операцию плюс проверки кодов 401, 403, 404, 422. Минимум — двенадцать тестов.глава 6.3
Сверка файлаexport_openapi.py --check: выгруженное описание совпадает с кодом.глава 3.1
ЛинтерНабор spectral:oas плюс минимум одно своё правило из вашего стандарта.глава 6.2
СборкаВсё перечисленное запускается само при push и pull request.глава 6.4
Признак готовности

Склонируйте свой репозиторий в пустую папку, установите зависимости и запустите проверки. Если всё зелёное без единой правки «по месту» — работа собрана правильно.

§8Шаг 7. Документы репозитория

ФайлЧто в нёмГлава
README.mdЧто за API, как запустить, ссылка на документацию и стандарт—
docs/API_STYLE_GUIDE.mdСвои правила с MUST, SHOULD, MAY и способом проверки каждого6.1
docs/VERSIONING.mdЧто считаете несовместимым изменением и почему5.2
docs/adr/0001-….mdОдно архитектурное решение с вариантами и последствиями5.4
CHANGELOG.mdХотя бы одна запись версии по Keep a Changelog5.4
.github/PULL_REQUEST_TEMPLATE.mdСвой шаблон с типом изменения и чек-листом7.1

Стандарт пишется под ваш API. Переписывать в него правила про Idempotency-Key, если вы этот заголовок не поддерживаете, не нужно: правило, которого нет в коде, на проверке заметно сразу.

§9Порядок работы с Git

  1. Отдельная ветка на изменение. Не пишите в main напрямую — иначе не увидите, как работают проверки в pull request.
  2. Небольшие изменения. «Добавил операцию + тесты + запись в CHANGELOG» — хороший размер. «Сделал всё» — плохой.
  3. Описание изменения по своему шаблону. Заполняйте его честно, включая тип изменения.
  4. Дождитесь сборки. Красная — читайте вывод, он написан для вас.
  5. Объединяйте только зелёное. Это и есть привычка, ради которой строилась вся глава 6.4.

Заведите хотя бы один pull request с намеренно несовместимым изменением и покажите, что проверка его поймала, — как это сделано в учебном репозитории. Такое изменение не объединяют — оно остаётся в репозитории как подтверждение того, что проверка работает.

§10Частые ошибки

Скопировать учебный проект и переименоватьВидно сразу: в стандарте остаются правила про обращения, а операции — про бронирования.
Слишком большая предметная областьНе хватит времени на проверки и документы — а именно они здесь главное.
Писать код раньше контрактаПотом переделывать описание под то, что получилось, и терять смысл работы.
Все ответы 200Создание — 201, удаление — 204, ненайденное — 404.
Правила в стандарте без проверкиКаждое правило должно ссылаться на тест, правило линтера или пункт ревью.
Описание только в памяти сервисаФайл должен лежать в репозитории, иначе нечего сравнивать и нечего публиковать.
Всё одним коммитом в последний деньИстория изменений — тоже часть работы, и по ней видно, как она делалась.

Справочник «Стандартизация HTTP API» · модуль 8 · глава 8.1Макаров Максим Николаевич

Кадр