Зачем API нужно версионирование
API эволюционируют: добавляются функции, меняются модели данных, заменяются старые паттерны. Без версионирования любое изменение может сломать существующих клиентов. Версионирование позволяет несовместимым изменениям сосуществовать со старыми версиями.
Breaking vs. Non-Breaking изменения
Non-breaking (безопасны без новой версии):
- Добавление опциональных полей в ответы
- Добавление новых endpoint-ов
- Добавление опциональных query-параметров
- Ослабление правил валидации
Breaking (требуют новой версии):
- Удаление или переименование поля
- Изменение типа данных поля
- Превращение опционального поля в обязательное
- Изменение структуры URL
- Изменение механизмов аутентификации
Стратегии версионирования
Версионирование через URL Path
Самый распространённый подход:
GET /api/v1/users
GET /api/v2/users
Плюсы: Легко видеть, кешировать, маршрутизировать Минусы: URL меняется между версиями
Версионирование через заголовки
GET /api/users
Accept: application/vnd.myapi.v2+json
Плюсы: Чистые URL Минусы: Скрыто, сложнее отлаживать
Версионирование через Query Parameter
GET /api/users?version=2
Плюсы: Легко переключать, видно в URL Минусы: Путаница с фильтрацией, проблемы кеширования
Сравнение
| Аспект | URL Path | Header | Query Param |
|---|---|---|---|
| Видимость | Высокая | Низкая | Средняя |
| Кеширование | Просто | Сложно | Сложно |
| Маршрутизация в gateway | Просто | Умеренно | Умеренно |
| Тестирование в браузере | Просто | Сложно | Просто |
| Распространённость | Максимальная | Средняя | Низкая |
Тестирование версионирования API
Тесты обратной совместимости
Для каждой новой версии проверяйте:
- Структура ответа: Клиенты v1 получают формат v1
- Наличие полей: Поля v1 не удалены
- Типы данных: Без изменений типов в v1
- Формат ошибок: Ответы об ошибках v1 без изменений
- Аутентификация: Механизмы v1 работают
Тесты по версиям
| Тест | v1 | v2 |
|---|---|---|
| GET /users | {name: "Alice"} | {firstName: "Alice", lastName: "..."} |
| Пагинация | ?page=1&per_page=20 | ?cursor=abc&limit=20 |
| Формат ошибок | {error: "Not found"} | {error: {code: "NOT_FOUND", message: "..."}} |
Тестирование устаревания
При устаревании версии проверяйте:
- Заголовки устаревания:
Deprecation: true
Sunset: Sat, 01 Mar 2026 00:00:00 GMT
Link: </api/v2/docs>; rel="successor-version"
- Заголовки предупреждений с информацией об устаревании
- Ссылки на документацию в ответе или заголовках
- Сроки прекращения: Устаревшая версия работает до указанной даты
- После прекращения: Возвращает 410 Gone или перенаправляет
Поведение версии по умолчанию
Что происходит без указания версии:
- API использует последнюю версию?
- API использует v1 (безопаснее для совместимости)?
- API возвращает ошибку, требуя явную версию?
Консистентность данных между версиями
Данные из v1 должны быть доступны в v2:
1. POST /api/v1/users → Создать пользователя (формат v1)
2. GET /api/v2/users/{id} → Должен вернуть формат v2
3. PUT /api/v2/users/{id} → Обновить в формате v2
4. GET /api/v1/users/{id} → Должен вернуть формат v1
Тестирование миграции
При переходе с v1 на v2:
- Проверить наличие v2-эквивалентов для всех функций v1
- Протестировать трансформацию данных v1 в ответах v2
- Проверить документированные альтернативы удалённых функций
- Убедиться, что токены работают в обеих версиях
Распространённые баги версионирования
| Баг | Как обнаружить |
|---|---|
| v1 содержит поля v2 | Сравнить схему v1 с документацией |
| v2 ломает контракт v1 | Запустить тесты v1 на текущем деплое |
| Нет уведомления об устаревании | Проверить заголовки устаревших версий |
| Несогласованность данных | Создать в v1, прочитать в v2, сравнить |
| Версия по умолчанию меняется | Тестировать запросы без явной версии |
Практическое упражнение
- Сравните версии: Сравните одну и ту же операцию в разных версиях API.
- Проверьте совместимость: Отправляйте запросы к обеим версиям, проверяйте данные.
- Создайте чек-лист миграции: Для гипотетической миграции v1 → v2 перечислите все изменения.
- Проверьте устаревание: Найдите deprecated endpoint и проверьте заголовки.
Ключевые выводы
- Версионирование позволяет несовместимым изменениям сосуществовать со старыми версиями
- URL path versioning — самый распространённый; header versioning — наиболее REST-совместимый
- Breaking changes требуют новых версий; non-breaking — нет
- Тестируйте обратную совместимость, запуская старые тесты на новых деплоях
- Проверяйте коммуникацию устаревания: заголовки, даты, документацию и руководства по миграции