Версионирование API
Версионирование API — стратегия управления изменениями контракта API таким образом, чтобы существующие клиенты продолжали работать после выхода новых версий.
Зачем нужно
API — публичный контракт. Любое breaking change (переименование поля, изменение типа, удаление эндпоинта) ломает всех клиентов. Версионирование позволяет вводить несовместимые изменения без мгновенного разрушения экосистемы: старые клиенты остаются на v1, новые используют v2, даётся время на миграцию.
Где используется
- Публичные REST API с внешними разработчиками (GitHub, Stripe)
- Внутренние API при смене контракта между командами
- Мобильные приложения (нельзя форсировать обновление у всех пользователей)
- GraphQL — deprecation полей вместо версионирования
Стратегии версионирования
1. URL-версионирование (наиболее распространённое)
GET /api/v1/users
GET /api/v2/users
Плюсы: явное, легко тестировать, видно в логах
Минусы: «нарушает» принципы REST (URL должен идентифицировать ресурс)
2. Версия в заголовке Accept
GET /api/users HTTP/1.1
Accept: application/vnd.myapp.v2+json
# Ответ
HTTP/1.1 200 OK
Content-Type: application/vnd.myapp.v2+json
3. Кастомный заголовок
GET /api/users HTTP/1.1
API-Version: 2
4. Query-параметр (не рекомендуется)
GET /api/users?version=2
Реализация в Express
// Вариант 1: Отдельные роутеры для версий
const v1Router = require('./routes/v1');
const v2Router = require('./routes/v2');
app.use('/api/v1', v1Router);
app.use('/api/v2', v2Router);
// Вариант 2: Через заголовок
app.get('/api/users', (req, res) => {
const version = req.headers['api-version'] || '1';
if (version === '2') {
return res.json(usersV2);
}
res.json(usersV1);
});
Семантическое версионирование (SemVer)
MAJOR.MINOR.PATCH
v2.1.3
MAJOR — breaking changes (переименование/удаление полей, смена структуры)
MINOR — обратно совместимые дополнения (новые поля, новые эндпоинты)
PATCH — исправления багов без изменения контракта
Для публичных API версионируют по MAJOR: v1, v2, v3
Breaking vs Non-breaking изменения
✅ Non-breaking (обратно совместимые):
- Добавление нового поля в ответ
- Добавление нового необязательного параметра
- Добавление нового эндпоинта
- Ослабление валидации (было required → стало optional)
❌ Breaking (ломающие):
- Переименование поля (name → fullName)
- Изменение типа (string → array)
- Удаление поля или эндпоинта
- Изменение формата (дата как "2024-01-15" → Unix timestamp)
- Ужесточение валидации
Стратегия deprecation
# Предупреждение об устаревании через заголовки
HTTP/1.1 200 OK
Deprecation: true
Sunset: Sat, 01 Jan 2026 00:00:00 GMT
Link: <https://api.example.com/v2/users>; rel="successor-version"
Частые ошибки
- Нет версионирования с самого начала — потом невозможно добавить без боли
- Breaking changes в patch/minor релизах — клиенты ломаются без предупреждения
- Бесконечная поддержка всех версий — создаёт технический долг
- Не уведомляют клиентов о deprecation заблаговременно (минимум 6 месяцев)