Модуль 7 · Репозиторий API

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

Глава 7.3

7.3

Опубликованная
документация

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

Категория
Репозиторий
Уровень
Средний
Связанные главы
3.4 Swagger UI и ReDoc · 4.1 Problem Details · 6.4 CI
Зачем это знать
Чтобы контракт был доступен клиенту без вашего участия

§1Три способа отдать документацию

СпособКому доступноКогда годится
/docs и /redoc у запущенного сервисаТому, кто дотянулся до сервиса по сетиРазработка, внутренний контур
Файл openapi.yaml в репозиторииТому, у кого есть доступ к репозиториюИнструменты, сравнение версий, ревью
Статический сайт документацииВсем, у кого есть ссылкаПубличный или межкомандный API

Третий способ нужен потому, что первые два требуют доступа, которого у читателя может не быть. Статический сайт не нуждается ни в запущенном сервисе, ни в правах на репозиторий: это обычные HTML-страницы.

Есть и вторая причина, специфическая для нашего контракта. Поле type в Problem Details содержит адрес, по которому RFC 9457 требует открывать документацию о виде проблемы. Пока страницы не опубликованы, это требование не выполнено: ссылка из ответа никуда не ведёт.

§2Сборка страницы ReDoc

ReDoc из главы 3.4 умеет работать не только в браузере у запущенного сервиса: та же документация собирается в один самодостаточный HTML-файл.

.github/workflows/docs.yml · шаг сборки
      - name: Build ReDoc page
        run: npx --yes @redocly/cli@2 build-docs openapi/openapi.yaml --output site/index.html
ВходФайл описания из репозитория — тот самый, что сверяется с кодом тестом из главы 6.3.openapi.yaml
ВыходОдна страница site/index.html. Всё нужное внутри: ни сервера, ни сборщика для показа не требуется.index.html
Версия закреплена@redocly/cli@2. То же правило, что и в главах 3.4, 5.2 и 6.2.предсказуемость

§3Страницы видов ошибок

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

scripts/build_docs.py · назначение
Поле type в Problem Details содержит адрес вида
https://…/api-standard-template/problems/http-404.
RFC 9457 (раздел 3.1.1) требует, чтобы по такому адресу открывалась документация
о виде проблемы. Скрипт создаёт site/problems/http-<код>.html для каждого кода,
который возвращает API, и копирует openapi.yaml в site/.
scripts/build_docs.py · источник содержимого
PROBLEMS = {
    401: ("Authentication required", "Нет заголовка Authorization или токен неизвестен.",
          "Передайте действующий токен: Authorization: Bearer <token>."),
    412: ("Precondition failed",
          "ETag из If-Match не совпадает с текущей версией обращения:"
          " его изменили после того, как вы его прочитали.",
          "Получите обращение заново, возьмите новый ETag и повторите изменение."),
    429: ("Too many requests", "Превышен лимит операций записи для токена.",
          "Повторите запрос через число секунд из заголовка Retry-After."),
    …
}

Семь видов ошибок — 401, 403, 404, 412, 422, 429, 500 — и у каждого три строки: название, когда возникает и что делать. Это те же три вопроса, что перечислены в главе 4.1.

§4Что на такой странице пишут

Третью строку — что делать клиенту — чаще всего пишут неудачно. Сравним два варианта:

Описание симптома
  • «Предусловие не выполнено.»
  • «Запрос отклонён.»
  • «Слишком много запросов.»
Инструкция
  • «Получите обращение заново, возьмите новый ETag и повторите изменение.»
  • «Исправьте поля из массива errors.»
  • «Повторите запрос через число секунд из Retry-After.»

Левый столбец повторяет то, что клиент уже знает из кода ответа. Правый сообщает порядок действий — за этим и переходят по ссылке из поля type.

Опубликованная страница вида проблемы http-412 с описанием причины и порядка действий
Страница problems/http-412. Открывается по адресу из поля type любого ответа 412. Разработчик клиента копирует адрес из ответа в браузер и получает инструкцию — без переписки с командой API.
Связь с чек-листом

В шаблоне pull request из главы 7.1 есть пункт: «у новых ответов с ошибкой есть страница вида проблемы в scripts/build_docs.py». Сборка этого не проверяет, поэтому пункт вынесен в чек-лист: новый код ошибки без страницы оставит в ответе нерабочую ссылку.

§5Выкладка при каждом изменении

Собранные страницы выкладываются автоматически: отдельная сборка docs.yml запускается при каждом изменении основной ветки.

.github/workflows/docs.yml · когда и что
name: Publish docs

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  build:
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v4
      - name: Build ReDoc page
        run: npx --yes @redocly/cli@2 build-docs openapi/openapi.yaml --output site/index.html
      - name: Build problem type pages
        run: python3 scripts/build_docs.py
      - uses: actions/upload-pages-artifact@v3
        with:
          path: site

  deploy:
    needs: build
    steps:
      - uses: actions/deploy-pages@v4
  1. Изменение попало в основную ветку — после зелёной сборки контракта и одобрения владельца.
  2. Собирается ReDoc из описания, которое тестом сверено с кодом.
  3. Собираются страницы ошибок и копируется openapi.yaml — чтобы файл можно было скачать по ссылке.
  4. Папка site выкладывается как готовый сайт.

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

Пункт workflow_dispatch добавляет кнопку ручного запуска. Она нужна нечасто — например, когда правки коснулись только текста страниц ошибок.

§6Права сборки и очередь

.github/workflows/docs.yml · права и очередь
permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: pages
  cancel-in-progress: true
contents: readЧитать репозиторий. Писать в него публикации не нужно — принцип наименьших прав.чтение
pages: writeЕдинственное право на запись: выложить сайт.публикация
concurrencyОдновременно публикуется только одна сборка; начатая ранее отменяется.очередь

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

§7Результат

Опубликованная документация ReDoc учебного проекта на GitHub Pages
Опубликованная документация. Тот же ReDoc, что и на локальном порту, но по постоянному адресу и без запущенного сервиса. Ссылку можно дать кому угодно — в том числе поставить в поле contact раздела info.

что опубликовано

index.htmlдокументация ReDoc по всему контракту
openapi.yamlсам файл описания — для инструментов и генераторов клиентов
problems/http-401 … http-500семь страниц видов ошибок, адреса из поля type

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

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

Документация только на локальном портуКлиент не может её открыть, и вопросы идут в переписку.
Публиковать вручнуюЧерез месяц на сайте окажется описание позапрошлой версии.
Адрес в поле type без опубликованной страницыТребование RFC 9457 не выполнено, ссылка ведёт в никуда.
На странице ошибки — только симптомКлиент пришёл за инструкцией, а получил пересказ кода ответа.
Новый код ошибки без новой страницыПроверяется человеком по чек-листу: сборка этого не поймает.
Публикация без очередиДве сборки подряд могут выложить версии не в том порядке.

§9Проверьте себя

  1. Назовите три способа отдать документацию и скажите, кому доступен каждый.
  2. Почему для нашего контракта публикация требуется стандартом?
  3. Что делает build-docs и почему полученный файл можно открыть без сервера?
  4. Какие три строки описывают каждый вид проблемы и какая из них важнее?
  5. Почему публикация вынесена в отдельную сборку, а не добавлена шагом в основную?
  6. Что предотвращает настройка concurrency с группой pages?
Что публикуетсяindex.html — ReDocopenapi.yaml — описаниеproblems/http-NNN
Сборка@redocly/cli@2 build-docsscripts/build_docs.pydeploy-pages@v4
Страница ошибкиназваниекогда возникаетчто делать
Настройкиpages: writeconcurrency: pagesworkflow_dispatch

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

Кадр