Модуль 5 · Версии и изменения

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

Глава 5.1

5.1

Четыре номера
и SemVer

В одном сервисе есть четыре независимых номера версии, и меняются они по разным поводам. В этой главе разобрано, какой номер за что отвечает, как устроено Semantic Versioning и где крупные компании указывают мажорную версию.

Категория
Версии
Уровень
Базовый
Связанные главы
5.2 Breaking changes · 3.2 Разделы документа · 5.4 CHANGELOG и ADR
Зачем это знать
Чтобы номер версии что-то значил и для вас, и для клиента

§1Четыре номера в одном сервисе

В учебном проекте есть четыре номера версии, и означают они разное.

НомерГде записанПримерЧто означает
Версия формата описанияopenapi в openapi/openapi.json3.1.0Каким форматом записан контракт; выбирает библиотека
Версия контрактаinfo.version в app/main.py1.1.0Состояние публичного контракта по SemVer
Мажорная версия в путиПрефикс маршрутов/api/v1С какой несовместимой редакцией работает клиент
Версия развёртыванияGitcommit 4ab219…Какой именно код сейчас запущен

Они меняются независимо. Запись openapi: 3.1.0 не означает, что у API версия 3.1, а выкладка нового коммита не меняет контракт. Об этом прямо предупреждает свод правил Zalando:

Zalando RESTful API Guidelines, правило 116 «MUST use semantic versioning»правила компании

«Note, this API specification document version is distinct from the OpenAPI Specification version (also required, e.g. openapi: 3.1.0), or the API Implementation version»

Перевод. Учтите: версия документа спецификации API — это не то же самое, что версия OpenAPI Specification (её тоже нужно указать, например openapi: 3.1.0) и не версия реализации API.

§2Semantic Versioning для контракта

Для info.version в проекте принят Semantic Versioning — три числа через точку, у каждого свой повод измениться.

Semantic Versioning 2.0.0спецификация

«MAJOR version when you make incompatible API changes
MINOR version when you add functionality in a backward compatible manner
PATCH version when you make backward compatible bug fixes»

Перевод. MAJOR — при несовместимых изменениях API; MINOR — при добавлении возможностей с сохранением обратной совместимости; PATCH — при исправлении ошибок с сохранением обратной совместимости.

MAJOR · 2.0.0Ломает существующих клиентов. Требует новой мажорной редакции и периода, когда старая и новая работают одновременно.ломает
MINOR · 1.2.0Добавляет возможности, ничего не ломая: новая операция, новый необязательный параметр, новое поле ответа.добавляет
PATCH · 1.1.1Исправляет поведение или описание, не меняя обещаний: уточнённая формулировка, исправленный пример, починенный код ответа.чинит

Польза номера в том, что клиент по нему понимает, нужно ли ему что-то делать. Переход с 1.1.0 на 1.2.0 он может пропустить; переход на 2.0.0 — не может.

Правило 116 в своде Zalando: MUST use semantic versioning с пояснением про отличие от версии OpenAPI
Правило в оригинале. Уровень требования — MUST: в этой компании номер контракта обязан следовать SemVer. Уровни требований разбираются в главе 6.1.

§3Где указывать мажорную версию

Когда несовместимое изменение всё же нужно, старая и новая редакции какое-то время работают рядом. Значит, клиент должен уметь выбрать, с какой он разговаривает. Способов четыре, и все они встречаются на практике.

В пути

/api/v1/tickets. Видно в любом журнале, ссылке и адресной строке. Редакции легко развести по разным экземплярам сервиса.

В заголовке

X-GitHub-Api-Version: 2026-03-10. Адрес ресурса не меняется, но версия не видна в ссылке и её легко забыть.

В параметре запроса

?api-version=2024-05-01. Видно в ссылке, но параметр приходится добавлять к каждому запросу.

В media type

Accept: application/vnd.servicedesk.v1+json. Формально самый «правильный» по духу HTTP и самый неудобный на практике.

Единственно правильного способа здесь нет: у каждого свои последствия. Поэтому выбор записывают отдельным документом — его устройство разобрано в главе 5.4.

§4Четыре решения крупных компаний

КтоГде версияПримерИсточник
GitHubЗаголовок, версия названа датойX-GitHub-Api-Version: 2026-03-10GitHub Docs, API Versions
Microsoft GraphПутьgraph.microsoft.com/v1.0/users, betaGuidelinesGraph.md
AzureПараметр запроса?api-version=2024-05-01Azure Guidelines.md
BoxВ имени файла описанияopenapi-v2025.0.jsonbox/box-openapi

Обратите внимание на две вещи. Во-первых, даже внутри одной компании решения расходятся: Microsoft Graph ставит версию в путь, а Azure — в параметр запроса, и это документы одной организации. Во-вторых, GitHub и Box называют версии датами, а не номерами SemVer: для публичного API дата понятнее, чем «мажорная двойка».

Страница GitHub Docs про версии REST API и заголовок X-GitHub-Api-Version
Версия датой. GitHub просит присылать заголовок с датой редакции и обещает поддерживать старые редакции не менее двух лет. Такое обещание — тоже часть контракта, только записанная словами, а не в описании.
Документ Azure Guidelines с требованием обязательного параметра api-version
Версия параметром. В Azure параметр api-version обязателен во всех запросах; правила даже задают текст сообщения, которое сервис возвращает, если параметр забыли.

§5Решение учебного проекта

В проекте выбран путь: /api/v1. Решение и его причины записаны в файле docs/adr/0001-api-versioning.md.

docs/adr/0001-api-versioning.md · выдержки
## Decision
Мажорная версия указывается в пути: /api/v1. Версия контракта ведётся по
Semantic Versioning в info.version. Совместимые изменения выпускаются без смены пути.

## Consequences
- Версия видна в любом логе, ссылке и в адресной строке Swagger UI.
- Старую и новую редакции можно направить на разные экземпляры сервиса правилом gateway.
- Кэши и CDN различают редакции без настройки Vary.
- Нельзя выпустить несовместимое изменение одной операции, не выпуская /api/v2 целиком.

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

§6Как номер меняется на практике

Посмотрим на настоящую историю учебного контракта: от 1.0.0 к 1.1.0.

CHANGELOG.md · что вошло в 1.1.0
### Added
- Заголовок X-Request-Id в каждом ответе.
- ETag в ответах с одним обращением, 304 на совпавший If-None-Match.
- If-Match в PATCH, ответ 412 при устаревшей версии.
- Idempotency-Key в POST: повтор с тем же ключом не создаёт второе обращение.
- Лимит операций записи: 429 с Retry-After, заголовки X-RateLimit-*.

### Deprecated
- GET /api/v1/tickets/open — используйте GET /api/v1/tickets?status=open.
  1. Все изменения — добавления. Новые заголовки, новые коды ответов в новых ситуациях. Ни одна существующая операция не изменила обещаний.
  2. Значит, это MINOR: 1.0.0 → 1.1.0. Путь остаётся /api/v1, клиентам ничего делать не нужно.
  3. Пометка устаревания не удаляет операцию. Операция GET /tickets/open помечена устаревшей, но работает. Само по себе это совместимое изменение; несовместимым станет её удаление — и оно ждёт версии 2.0.0.
Почему устаревание не ломает

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

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

Путать версию OpenAPI с версией APIopenapi: 3.1.0 — про формат файла, а не про ваш сервис.
Повышать MAJOR при каждом измененииТогда номер перестаёт что-либо сообщать, а клиенты — на него смотреть.
Менять контракт, не трогая номерКлиент не может отличить старое описание от нового и не знает, нужно ли ему что-то делать.
Версия только в заголовке и нигде большеВ журналах и ссылках не видно, с какой редакцией работал клиент, — разбор жалобы усложняется.
Выбрать способ версионирования и не записать почемуПричина выбора забывается, и при следующем обсуждении доводы приходится восстанавливать заново.

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

  1. Назовите четыре номера учебного проекта и скажите, кто меняет каждый из них.
  2. Какая часть SemVer меняется при добавлении нового необязательного параметра? А при удалении поля ответа?
  3. Перечислите четыре места, куда можно поместить мажорную версию, и назовите по одному минусу каждого.
  4. Почему в одной компании — Microsoft — два API версионируются по-разному?
  5. Почему переход 1.0.0 → 1.1.0 в учебном проекте не потребовал пути /api/v2, хотя добавилось семь новых возможностей?
  6. Зачем в документе решения записывают отрицательные последствия выбора?
Четыре номераopenapi: 3.1.0 — форматinfo.version — контракт/api/v1 — редакцияcommit — развёртывание
SemVerMAJOR — ломаетMINOR — добавляетPATCH — чинит
Где версияпутьзаголовокпараметр запросаmedia type
В проекте/api/v1 + SemVerADR 0001

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

Кадр