Модуль 6 · Стандарт и его проверка

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

Глава 6.1

6.1

API
Style Guide

Правила, разобранные в предыдущих модулях — адреса, методы, коды, заголовки, версии, — собирают в один документ: внутренний стандарт проекта. У каждого правила в нём указаны сила требования и способ проверки.

Категория
Стандарт
Уровень
Базовый
Связанные главы
6.2 Линтер Spectral · 6.3 Контрактные тесты · 7.4 Стандарты компаний
Зачем это знать
Чтобы договорённости команды жили дольше, чем память участников

§1Зачем нужен свой стандарт

Пока сервис пишет один человек, договорённости живут у него в голове. Как только появляется второй, начинаются разночтения: у одного created_at, у другого createdAt; один возвращает 200 при создании, другой 201. По отдельности такие расхождения невелики, но вместе они делают API неоднородным: клиенту приходится помнить исключения для каждой операции.

Без стандарта
  • решение зависит от того, кто пишет
  • спор на каждом ревью заново
  • клиент учит исключения наизусть
  • новый участник узнаёт правила случайно
Со стандартом
  • решение уже принято
  • ревью сверяется с документом
  • клиент видит единообразие
  • новый участник читает один файл

В учебном проекте это файл docs/API_STYLE_GUIDE.md. Он занимает около сотни строк и состоит из решений, разобранных в предыдущих модулях.

§2MUST, SHOULD, MAY: RFC 2119

Первое, что задаёт документ, — как читать силу требования. Значения этих слов определены отдельным стандартом, RFC 2119; поэтому в текстах стандартов их пишут заглавными буквами.

docs/API_STYLE_GUIDE.md · шапка
Внутренний стандарт проекта. Сила требования обозначается словами из RFC 2119:
MUST — обязательно, SHOULD — рекомендуется, отступление нужно обосновать,
MAY — допускается.
MUST · MUST NOTОбязательно. Отступления нет: нарушение — ошибка, и его не пропускает проверка. «Каждый ответ MUST содержать X-Request-Id.»обязательно
SHOULD · SHOULD NOTРекомендуется. Отступить можно, но нужно понимать последствия и объяснить причину. «Успешное удаление SHOULD возвращать 204.»обоснуй
MAYДопускается. Возможность, а не требование. «POST MAY принимать Idempotency-Key.»можно

Разница между MUST и SHOULD проявляется на ревью. К MUST вопрос один: выполнено или нет. К SHOULD вопрос другой: если не выполнено, то почему — и ответ записывается.

Как читать уровень требования в чужих стандартах

Открывая свод правил Zalando или RFC, сначала смотрите на слово уровня. Правило 182 про ETag — это MAY: «можно предусмотреть». Правило 153 про 429 — MUST. Одинаково оформленные пункты списка имеют разный вес, и без учёта уровня свод читается неверно.

§3Как выбрать уровень требования

Выбор уровня — основная работа при написании стандарта. Ориентироваться можно так:

Вопрос о правилеОтветУровень
Нарушение ломает клиента или делает API непредсказуемым?даMUST
Нарушение делает API хуже, но есть случаи, когда оправдано?даSHOULD
Это возможность, которой можно пользоваться, а можно нет?даMAY
Нарушение вообще незаметно снаружи?даправилу не место в стандарте API

Последняя строка отделяет внутренние соглашения о коде — имена переменных, структуру папок, стиль коммитов — от стандарта API. Стандарт API описывает только то, что видит клиент.

Всё сделать MUST

Соблазнительно и вредно: документ становится невыполнимым, его начинают нарушать целиком, а не по пунктам. Если MUST нарушается регулярно — это был SHOULD.

Всё сделать SHOULD

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

§4Каждое правило проверяемо

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

docs/API_STYLE_GUIDE.md · выдержки
- URI MUST use nouns: /tickets, а не /getTickets (.spectral.yaml: paths-no-verbs).
- Все пути MUST начинаться с мажорной версии: /api/v1/ (tests/test_contract.py).
- Каждый ответ MUST содержать X-Request-Id (tests/test_http_features.py).
- Свойства MUST быть в snake_case: created_at, ticket_id (json-properties-snake-case).
- Создание ресурса MUST выполняться POST на коллекцию и возвращать 201 Created
  с заголовком Location (tests/test_tickets.py).

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

ЛинтерПроверяет описание: имена путей, регистр свойств, наличие operationId, media type ошибок. Глава 6.2..spectral.yaml
Тесты описанияПроверяют структуру контракта: префикс версии, уникальность operationId, требование токена. Глава 6.3.test_contract.py
Тесты поведенияПроверяют, что сервис действительно так отвечает: 201 с Location, 412 на устаревший If-Match.test_tickets.py
РевьюВсё, что машина не поймает: осмысленность формулировок, уместность нового поля, качество примеров.человек

§5Структура документа

Разделы удобно строить по пути запроса — от адреса к телу, — а не по важности.

docs/API_STYLE_GUIDE.md

1. URIсуществительные, множественное число, вложенность, префикс версии
2. HTTPкакой метод что делает, какой код когда возвращается
3. ЗаголовкиX-Request-Id, ETag, If-Match, лимиты, Idempotency-Key, CORS
4. Операции OpenAPIoperationId, теги, описания ответов, примеры
5. JSONsnake_case, формат даты, отдельные схемы, пагинация
6. ОшибкиProblem Details, набор кодов, что нельзя раскрывать
7. ВерсииSemVer, путь /api/v1, устаревание

Такой порядок удобен читателю: проверяя своё изменение, он идёт сверху вниз ровно в том порядке, в каком формируется запрос.

§6Правило без источника не правило

У каждого правила в учебном проекте есть отдельный документ-обоснование — docs/STANDARDS.md. Там для каждого решения указан источник: раздел RFC, правило из свода компании или ссылка на документацию крупного API, с цитатой в оригинале и переводом.

docs/STANDARDS.md · вид одной записи
## 4. Формат ошибок: Problem Details

В проекте: app/problems.py, docs/ERRORS.md, страницы видов ошибок на GitHub Pages.

Источник: RFC 9457, раздел 3.1.1, Standards Track.

> If the type URI is a locator …, dereferencing it SHOULD provide human-readable
> documentation for the problem type …

Перевод: если URI в поле type является адресом …

Как это делают другие: Zalando — application/problem+json; Azure — своя структура
ошибки и заголовок x-ms-error-code.

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

Зачем нужен источник

Правило без источника обсуждается как мнение автора. Если правило подкреплено ссылкой на RFC или на свод компании, обсуждение сводится к одному вопросу: принимаем требование или записываем обоснованное отступление от него.

§7Своды крупных компаний

Собственный стандарт обычно составляют, опираясь на уже опубликованные своды правил.

СводЧем полезенОсобенность
Zalando RESTful API GuidelinesСамый подробный: каждое правило пронумеровано и имеет уровеньНа правило можно сослаться номером: «rule 176»
Microsoft API GuidelinesОтдельные своды для Azure и Microsoft GraphВнутри одной компании решения расходятся
adidas API GuidelinesКомпактный, читается за вечерХороший образец для небольшой команды
DigitalOceanПравила выражены готовым набором для линтераСтандарт и его проверка — один и тот же файл
Сайт Zalando RESTful API Guidelines со списком пронумерованных правил
Пронумерованные правила. Каждое правило — отдельный пункт с уровнем требования и постоянным номером. На такое правило удобно ссылаться в ревью и в собственном стандарте, что мы и делали во всех предыдущих модулях.
Репозиторий DigitalOcean с набором правил Spectral для их OpenAPI
Стандарт как код. У DigitalOcean правила стиля выражены прямо набором правил линтера. Это предельный случай принципа из §4: документ и проверка не расходятся, потому что это один файл.

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

Стандарт без уровней требованийНепонятно, что обязательно, а что пожелание, и на ревью спорят о каждом пункте.
Правило без способа проверкиСоблюдается первые две недели, потом забывается.
Всё объявить MUSTДокумент становится невыполнимым, и его перестают соблюдать целиком.
Правила о внутреннем устройствеИмена переменных и структура папок клиенту не видны — это другой документ.
Правило без источникаОбсуждается бесконечно, потому что спорят с автором, а не со стандартом.
Стандарт, который никто не читалДокумент нужно давать новому участнику в первый день и ссылаться на него в каждом ревью.

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

  1. Что означают MUST, SHOULD и MAY и чем отличается разговор на ревью для первых двух?
  2. Как выбрать уровень требования для нового правила? Приведите пример для каждого уровня.
  3. Почему правило «имена переменных в snake_case» не место в API Style Guide, а «свойства JSON в snake_case» — место?
  4. Назовите четыре способа проверки правил в учебном проекте.
  5. Из каких четырёх частей состоит запись в STANDARDS.md и зачем нужна последняя?
  6. Почему стандарт DigitalOcean, выраженный набором правил линтера, не может разойтись с проверкой?
Уровни · RFC 2119MUST — обязательноSHOULD — обоснуй отступлениеMAY — допускается
Проверка.spectral.yaml — описаниеtest_contract.py — структураtest_tickets.py — поведениеревью — смысл
Запись правилагде в кодеисточникпереводварианты у других
ОбразцыZalandoMicrosoftadidasDigitalOcean

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

Кадр