Вопрос 15 · Раздел 6

Как организовать версионирование REST API?

Когда вы меняете API (удаляете поля, меняете структуру), старые клиенты могут перестать работать. Версионирование позволяет поддерживать несколько версий одновременно.

Версии по языкам: English Russian Ukrainian

Junior Level

Версионирование API — это способ управления изменениями, чтобы не сломать существующих клиентов.

Зачем нужно версионирование?

Когда вы меняете API (удаляете поля, меняете структуру), старые клиенты могут перестать работать. Версионирование позволяет поддерживать несколько версий одновременно.

Основные стратегии:

1. Версия в URL — наиболее распространённый подход в индустрии (GitHub, Stripe, AWS). Его проще всего маршрутизировать и дебажить:

/api/v1/users
/api/v2/users

2. Версия в заголовке:

GET /users
Accept-Version: v2

3. Версия в типе контента:

GET /users
Accept: application/vnd.myapi.v2+json

Что считается “ломающим” изменением (Breaking Change)?

  • Удаление или переименование полей
  • Изменение структуры (объект стал массивом)
  • Новые обязательные поля
  • Изменение типа данных (Integer → String)

Middle Level

Стратегии версионирования

1. URI Versioning (/v1/users)

  • Плюс: Легко настраивать кэширование на CDN. Простое логирование и маршрутизация
  • Минус: URL меняется при каждой новой версии

2. Header Versioning (Accept-Version: v2)

  • Плюс: Один эндпоинт отдаёт разные версии
  • Минус: Требует заголовок Vary: Accept-Version, иначе кэш выдаст V1 пользователю V2

3. Media Type Versioning (Accept: application/vnd.myapi.v2+json)

  • Плюс: Ближе всего к духу REST по Ройу Филдингу (создателю REST), так как использует Content Negotiation. Однако на практике редко применяется из-за сложности отладки.
  • Минус: Сложнее в реализации и отладке

Contract Testing (Pact)

В микросервисах версионирование часто заменяется контрактным тестированием:

  • Потребитель (Consumer) описывает, какие поля ему нужны
  • Поставщик (Provider) проверяет при каждом билде, не сломал ли он ожидания клиентов
  • Позволяет делать “плавные” обновления без смены мажорной версии

API Gateway и Blue-Green Deployment

API Gateway (Kong, Spring Cloud Gateway) может выполнять роль Version Router:

  • 10% трафика с заголовком v2 → новая версия (Canary Release — канареечный релиз: новая версия получает небольшой процент трафика, например 10%. Если ошибок нет — трафик постепенно переводится полностью).
  • 90% → старая версия

Производительность

  • Sunset Policy (RFC 8594): Всегда устанавливайте дату “смерти” старой версии. Используйте заголовок Sunset
  • Backward Compatibility Layer: Создайте “адаптер” на уровне API Gateway, который трансформирует запросы старого формата в новый

Edge Cases

  • Database Schema: Самое сложное — если новая версия требует изменения схемы БД
    • Решение: Стратегия “Expand and Contract” (Расширь и сожми) — миграция БД без даунтайма: 1) Expand — добавляем новую колонку, не удаляя старую. 2) Мигрируем данные. 3) Contract — удаляем старую колонку.
  • Side Effects: Если v1 пишет в таблицу A, а v2 — в таблицу B, убедитесь, что аналитика учитывает оба источника

Senior Level

Управление контрактом

Версионирование — это управление контрактом между поставщиком и потребителем. Любое изменение, требующее изменений в коде клиента, является “ломающим”.

Что ломает контракт?

  • Удаление или переименование полей в JSON
  • Изменение структуры (объект стал массивом)
  • Изменение логики валидации (новое обязательное поле)
  • Изменение типа данных (Integer → String)

Инфраструктура и Тестирование

Contract Testing (Pact)

Позволяет делать “плавные” обновления без смены мажорной версии:

  • Consumer описывает ожидания
  • Provider проверяет совместимость при каждом билде

API Gateway и Canary Release

API Gateway выполняет роль Version Router:

  • Canary Release: 10% трафика на v2, 90% на v1
  • Мониторинг ошибок на новой версии перед полным переключением

Производительность и Highload

Sunset Policy (RFC 8594)

Используйте заголовок Sunset для предупреждения клиентов об отключении версии:

Sunset: Sat, 31 Dec 2026 23:59:59 GMT

Backward Compatibility Layer

Если поддержка старой версии дорога — создайте прокси-адаптер на API Gateway. Это позволит удалить старый код из основного микросервиса.

Диагностика

  • Metric: api_version_usage_total: Считайте запросы к каждой версии. Это единственный способ аргументированно отключить старую версию
  • Deprecation Header: Используйте Deprecation: true для автоматизированного мониторинга использования устаревших методов
  • Database Strategy: Expand and Contract — сначала добавляем новые колонки, потом мигрируем, потом удаляем старые

🎯 Шпаргалка для интервью

Обязательно знать:

  • 3 стратегии: URL (/v1/users), заголовок (Accept-Version: v2), Media Type (application/vnd.myapi.v2+json)
  • URL Versioning — наиболее распространённый подход (GitHub, Stripe, AWS), проще маршрутизировать
  • Breaking Changes: удаление/переименование полей, изменение структуры, новые обязательные поля, смена типа данных
  • Contract Testing (Pact) позволяет обновлять API без смены мажорной версии
  • Sunset Policy (RFC 8594): заголовок Sunset предупреждает об отключении версии
  • Expand and Contract — миграция БД без даунтайма: добавить колонку → мигрировать → удалить старую
  • API Gateway может выполнять роль Version Router с Canary Release (10% на v2)

Частые уточняющие вопросы:

  • Что ломает контракт API? — Удаление полей, изменение структуры, новые обязательные поля, смена типа данных
  • Почему Media Type Versioning редко используется? — Сложнее в реализации и отладке, хотя ближе к духу REST
  • Что такое Contract Testing? — Consumer описывает ожидания, Provider проверяет совместимость при каждом билде
  • Как мигрировать БД при версионировании? — Expand and Contract: добавляем новое, мигрируем данные, удаляем старое

Красные флаги (НЕ говорить):

  • «Версия в URL — это антипаттерн» — это самый распространённый подход в индустрии
  • «Non-breaking changes не требуют версионирования» — даже добавление поля может сломать клиентов
  • «Contract Testing заменяет версионирование полностью» — позволяет делать плавные обновления, но не отменяет его
  • «Media Type Versioning — лучший выбор» — теоретически верен, но на практике редко применяется

Связанные темы:

  • [[Что такое REST]]
  • [[Что такое RESTful API дизайн]]
  • [[Что такое Content-Type header]]
  • [[Что такое Accept header]]
  • [[Как правильно именовать REST endpoints]]