Введение
Версионирование API — это критически важный аспект разработки, который позволяет вносить изменения в API без поломки существующих клиентов. Правильная стратегия версионирования обеспечивает обратную совместимость и упрощает эволюцию API.
В этом руководстве мы разберем три основных подхода к версионированию API: URL versioning, Header versioning и Query parameter versioning. Узнаем их преимущества и недостатки, и когда какой подход использовать.
✅ Что вы узнаете:
- ✅ URL versioning (/api/v1/) — самый популярный подход
- ✅ Header versioning (Accept header) — RESTful подход
- ✅ Query parameter versioning (?version=1) — простой подход
- ✅ Сравнение подходов и их особенности
- ✅ Best practices версионирования
- ✅ Обратная совместимость и миграция
- ✅ Примеры реализации на разных языках
- ✅ Распространенные ошибки и как их избежать
📋 Содержание
Зачем нужно версионирование API? 🤔
API эволюционируют со временем: добавляются новые функции, изменяются существующие, удаляются устаревшие. Без версионирования любые изменения могут сломать существующих клиентов.
✅ Преимущества версионирования:
- Обратная совместимость — старые клиенты продолжают работать
- Постепенная миграция — клиенты могут мигрировать в своем темпе
- Эволюция API — можно вносить breaking changes в новых версиях
- Контроль изменений — четкое разделение версий
- Документация — каждая версия имеет свою документацию
⚠️ Когда нужна новая версия:
- Удаление или переименование endpoints
- Изменение структуры ответов (breaking changes)
- Изменение обязательных параметров
- Изменение формата данных
- Удаление полей из ответов
URL Versioning 🔗
URL Versioning — это самый популярный подход, при котором версия API
указывается в URL пути, например /api/v1/users или /api/v2/users.
Примеры URL Versioning:
GET /api/v1/users— версия 1GET /api/v2/users— версия 2POST /api/v1/users— создание пользователя v1GET /api/v1/users/123— получение пользователя v1
Преимущества URL Versioning
✅ Плюсы:
- Простота — легко понять и использовать
- Прозрачность — версия видна в URL
- Кэширование — легко кэшировать по URL
- Документация — легко документировать разные версии
- Отладка — легко увидеть версию в логах
Недостатки URL Versioning
❌ Минусы:
- Нарушение REST — версия не является ресурсом
- Дублирование кода — нужно поддерживать несколько версий
- URL загрязнение — версия в каждом URL
Реализация URL Versioning
Node.js (Express)
// routes/v1/users.js
const express = require('express');
const router = express.Router();
router.get('/users', (req, res) => {
res.json({
version: 'v1',
users: [
{ id: 1, name: 'John', email: 'john@example.com' }
]
});
});
module.exports = router;
// routes/v2/users.js
const express = require('express');
const router = express.Router();
router.get('/users', (req, res) => {
res.json({
version: 'v2',
users: [
{
id: 1,
name: 'John',
email: 'john@example.com',
createdAt: '2025-01-01' // Новое поле в v2
}
]
});
});
module.exports = router;
// app.js
const express = require('express');
const v1Routes = require('./routes/v1/users');
const v2Routes = require('./routes/v2/users');
const app = express();
app.use('/api/v1', v1Routes);
app.use('/api/v2', v2Routes);
app.listen(3000);
Python (Flask)
# routes/v1/users.py
from flask import Blueprint, jsonify
v1_bp = Blueprint('v1', __name__, url_prefix='/api/v1')
@v1_bp.route('/users', methods=['GET'])
def get_users_v1():
return jsonify({
'version': 'v1',
'users': [
{'id': 1, 'name': 'John', 'email': 'john@example.com'}
]
})
# routes/v2/users.py
from flask import Blueprint, jsonify
v2_bp = Blueprint('v2', __name__, url_prefix='/api/v2')
@v2_bp.route('/users', methods=['GET'])
def get_users_v2():
return jsonify({
'version': 'v2',
'users': [
{
'id': 1,
'name': 'John',
'email': 'john@example.com',
'createdAt': '2025-01-01' # Новое поле в v2
}
]
})
# app.py
from flask import Flask
from routes.v1.users import v1_bp
from routes.v2.users import v2_bp
app = Flask(__name__)
app.register_blueprint(v1_bp)
app.register_blueprint(v2_bp)
if __name__ == '__main__':
app.run(port=5000)
Header Versioning 📋
Header Versioning — это подход, при котором версия API указывается в
HTTP заголовке, обычно в заголовке Accept, например
Accept: application/vnd.api+json;version=1.
Примеры Header Versioning:
Accept: application/vnd.api+json;version=1Accept: application/vnd.api+json;version=2API-Version: 1(кастомный заголовок)X-API-Version: 2(кастомный заголовок)
Преимущества Header Versioning
✅ Плюсы:
- Чистота URL — версия не в URL
- RESTful — соответствует принципам REST
- Гибкость — можно использовать разные заголовки
- Content Negotiation — стандартный HTTP механизм
Недостатки Header Versioning
❌ Минусы:
- Менее очевидно — версия не видна в URL
- Сложнее отладка — нужно проверять заголовки
- Кэширование — сложнее кэшировать
- Браузеры — сложнее тестировать в браузере
Реализация Header Versioning
// middleware/versionMiddleware.js
function versionMiddleware(req, res, next) {
const acceptHeader = req.headers.accept || '';
const apiVersionHeader = req.headers['api-version'];
// Парсим версию из Accept header
const acceptMatch = acceptHeader.match(/version=(\d+)/);
const version = apiVersionHeader || (acceptMatch ? acceptMatch[1] : '1');
req.apiVersion = version;
next();
}
// routes/users.js
const express = require('express');
const router = express.Router();
router.get('/users', versionMiddleware, (req, res) => {
const version = req.apiVersion;
if (version === '2') {
return res.json({
version: 'v2',
users: [
{
id: 1,
name: 'John',
email: 'john@example.com',
createdAt: '2025-01-01'
}
]
});
}
// По умолчанию v1
res.json({
version: 'v1',
users: [
{ id: 1, name: 'John', email: 'john@example.com' }
]
});
});
module.exports = router;
Query Parameter Versioning ❓
Query Parameter Versioning — это подход, при котором версия API
указывается в query параметре, например /api/users?version=1 или
/api/users?v=2.
Примеры Query Parameter Versioning:
GET /api/users?version=1GET /api/users?version=2GET /api/users?v=1(сокращенная форма)GET /api/users?api_version=2
Преимущества Query Parameter Versioning
✅ Плюсы:
- Простота — легко добавить параметр
- Гибкость — можно сделать опциональным
- Браузеры — легко тестировать в браузере
Недостатки Query Parameter Versioning
❌ Минусы:
- Не RESTful — версия не является частью ресурса
- Загрязнение URL — параметр в каждом запросе
- Кэширование — сложнее кэшировать
- Менее популярен — реже используется
Реализация Query Parameter Versioning
// routes/users.js
const express = require('express');
const router = express.Router();
router.get('/users', (req, res) => {
const version = req.query.version || req.query.v || '1';
if (version === '2') {
return res.json({
version: 'v2',
users: [
{
id: 1,
name: 'John',
email: 'john@example.com',
createdAt: '2025-01-01'
}
]
});
}
// По умолчанию v1
res.json({
version: 'v1',
users: [
{ id: 1, name: 'John', email: 'john@example.com' }
]
});
});
module.exports = router;
Сравнение подходов 📊
| Критерий | URL Versioning | Header Versioning | Query Parameter |
|---|---|---|---|
| Простота | ✅ Очень простая | ⚠️ Средняя | ✅ Простая |
| Прозрачность | ✅ Версия в URL | ❌ Версия в заголовке | ⚠️ Версия в параметре |
| RESTful | ❌ Не полностью | ✅ Да | ❌ Нет |
| Кэширование | ✅ Легко | ⚠️ Сложнее | ⚠️ Сложнее |
| Отладка | ✅ Легко | ⚠️ Нужны инструменты | ✅ Легко |
| Браузеры | ✅ Легко тестировать | ⚠️ Нужны инструменты | ✅ Легко тестировать |
| Популярность | ✅ Очень популярна | ⚠️ Средняя | ❌ Низкая |
Best Practices 📚
✅ Рекомендации по версионированию:
- Используйте семантическое версионирование — MAJOR.MINOR.PATCH (v1.0.0)
- Документируйте изменения — changelog для каждой версии
- Поддерживайте старые версии — минимум 6-12 месяцев
- Уведомляйте о deprecation — заранее предупреждайте об удалении
- Используйте одну стратегию — не смешивайте подходы
- Версионируйте только при необходимости — не создавайте версии без breaking changes
- Тестируйте обратную совместимость — автоматические тесты
Семантическое версионирование
📌 Формат: MAJOR.MINOR.PATCH
- MAJOR — breaking changes (v1 → v2)
- MINOR — новые функции, обратно совместимые (v1.0 → v1.1)
- PATCH — исправления багов (v1.0.0 → v1.0.1)
Deprecation Policy
// Пример ответа с предупреждением о deprecation
{
"data": { ... },
"deprecation": {
"version": "v1",
"sunset_date": "2026-06-01",
"link": "https://api.example.com/docs/migration-v1-to-v2"
},
"warning": "API v1 будет удален 1 июня 2026. Пожалуйста, мигрируйте на v2."
}
Обратная совместимость 🔄
Обратная совместимость означает, что старые версии API продолжают работать после выпуска новых версий. Это критически важно для API.
✅ Правила обратной совместимости:
- Добавление полей — безопасно (старые клиенты игнорируют)
- Удаление полей — breaking change (нужна новая версия)
- Изменение типов — breaking change
- Добавление endpoints — безопасно
- Удаление endpoints — breaking change
- Изменение обязательных параметров — breaking change
Стратегия миграции
План миграции на новую версию:
- Выпуск новой версии — параллельно со старой
- Уведомление о deprecation — за 6-12 месяцев
- Предоставление документации — гайд по миграции
- Поддержка обеих версий — минимум 6 месяцев
- Удаление старой версии — после миграции всех клиентов
Заключение
Выбор стратегии версионирования API зависит от требований проекта. URL versioning — самый популярный и простой подход, который подходит для большинства случаев. Header versioning — для RESTful API, где важна чистота URL. Query parameter versioning — простой, но менее рекомендуемый подход.
💡 Ключевые выводы:
- URL versioning — самый популярный и простой подход
- Header versioning — для RESTful API с чистыми URL
- Query parameter versioning — простой, но менее рекомендуемый
- Используйте семантическое версионирование
- Поддерживайте обратную совместимость
- Уведомляйте о deprecation заранее
- Документируйте изменения в каждой версии
Создайте Mock API с версионированием за 2 минуты
Хотите протестировать версионирование API? Создайте Mock API с помощью LightBox API и попробуйте различные стратегии версионирования без необходимости настраивать сложный backend.
Попробовать бесплатно →