Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Версионирование API
versioning

Версионирование API

URL, query params, headers — стратегии версионирования

Версионирование API в Django REST Framework

Версионирование позволяет изменять API без поломки существующих клиентов. DRF предоставляет несколько стратегий версионирования.

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

Версионирование API — практика поддержки нескольких версий API одновременно. Нужно, когда:

  • Изменяется формат ответа
  • Удаляются или переименовываются поля
  • Меняется логика работы
  • Добавляются breaking changes

Без версионирования: Изменение API ломает всех существующих клиентов.
С версионированием: Клиенты постепенно мигрируют на новую версию.

#Настройка версионирования

Глобальная настройка в settings.py:

REST_FRAMEWORK = { 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning', 'DEFAULT_VERSION': 'v1', 'ALLOWED_VERSIONS': ['v1', 'v2'], 'VERSION_PARAM': 'version', }

#URLPathVersioning

Версия в URL пути:

# settings.py REST_FRAMEWORK = { 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning', 'DEFAULT_VERSION': 'v1', 'ALLOWED_VERSIONS': ['v1', 'v2'], } # urls.py urlpatterns = [ path('api/<str:version>/', include(router.urls)), ] # views.py class ArticleViewSet(viewsets.ModelViewSet): queryset = Article.objects.all() def get_queryset(self): version = self.request.version if version == 'v2': return Article.objects.select_related('author').all() return Article.objects.all()

Запросы:

  • GET /api/v1/articles/ — версия 1
  • GET /api/v2/articles/ — версия 2

Преимущества:

  • Версия видна в URL
  • Легко тестировать
  • Кэширование по версиям

Недостатки:

  • URL не «чистый» (содержит версию)

#NamespaceVersioning

Версия через namespace URL:

# settings.py REST_FRAMEWORK = { 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning', 'DEFAULT_VERSION': 'v1', } # urls.py urlpatterns = [ path('api/v1/', include((router.urls, 'api'), namespace='v1')), path('api/v2/', include((router.urls, 'api'), namespace='v2')), ] # views.py class ArticleViewSet(viewsets.ModelViewSet): def get_queryset(self): version = self.request.version # 'v1' или 'v2' # Логика по версиям

Запросы:

  • GET /api/v1/articles/
  • GET /api/v2/articles/

Отличие от URLPathVersioning: Версия определяется через namespace, а не параметр URL.

#QueryParameterVersioning

Версия в query-параметре:

# settings.py REST_FRAMEWORK = { 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.QueryParameterVersioning', 'DEFAULT_VERSION': 'v1', 'VERSION_PARAM': 'version', } # urls.py urlpatterns = [ path('api/', include(router.urls)), # Без версии в пути ] # views.py class ArticleViewSet(viewsets.ModelViewSet): def get_queryset(self): version = self.request.version # Логика по версиям

Запросы:

  • GET /api/articles/?version=v1
  • GET /api/articles/?version=v2

Преимущества:

  • Чистый URL без версии
  • Легко изменить версию в запросе

Недостатки:

  • Версия не видна из URL
  • Сложнее кэшировать

#HostNameVersioning

Версия в поддомене:

# settings.py REST_FRAMEWORK = { 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.HostNameVersioning', 'DEFAULT_VERSION': 'v1', 'ALLOWED_VERSIONS': ['v1', 'v2'], 'HOSTNAME_VERSION_PATTERN': r'(?P<version>v\d+)\.', } # urls.py urlpatterns = [ path('api/', include(router.urls)), ]

Запросы:

  • GET http://v1.example.com/api/articles/
  • GET http://v2.example.com/api/articles/

Преимущества:

  • Чистый путь URL
  • Версия в домене

Недостатки:

  • Требует настройки DNS/сервера
  • Сложнее для локальной разработки

#AcceptHeaderVersioning

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

# settings.py REST_FRAMEWORK = { 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.AcceptHeaderVersioning', 'DEFAULT_VERSION': 'v1', } # views.py class ArticleViewSet(viewsets.ModelViewSet): def get_queryset(self): version = self.request.version

Запросы:

GET /api/articles/ Accept: application/json; version=1.0 # Или с медиа-типом: Accept: application/vnd.example.v1+json

Преимущества:

  • Чистый URL
  • Соответствует HTTP-спецификации

Недостатки:

  • Сложнее тестировать (нужно устанавливать заголовки)
  • Не видно из браузера

#Разные сериализаторы для разных версий

# serializers.py class ArticleSerializerV1(serializers.ModelSerializer): # Старый формат author_name = serializers.CharField(source='author.username', read_only=True) class Meta: model = Article fields = ['id', 'title', 'content', 'author_name', 'created_at'] class ArticleSerializerV2(serializers.ModelSerializer): # Новый формат с вложенным автором author = AuthorSerializer(read_only=True) class Meta: model = Article fields = ['id', 'title', 'content', 'author', 'created_at', 'updated_at'] # views.py class ArticleViewSet(viewsets.ModelViewSet): queryset = Article.objects.all() def get_serializer_class(self): if self.request.version == 'v2': return ArticleSerializerV2 return ArticleSerializerV1

#Разная логика для разных версий

class ArticleViewSet(viewsets.ModelViewSet): def get_queryset(self): version = self.request.version if version == 'v1': # Старая логика — только опубликованные return Article.objects.filter(is_published=True) elif version == 'v2': # Новая логика — все для авторизованных if self.request.user.is_authenticated: return Article.objects.all() return Article.objects.filter(is_published=True) return Article.objects.filter(is_published=True) def perform_create(self, serializer): version = self.request.version if version == 'v1': # V1 не позволяет устанавливать автора serializer.save(author=self.request.user) else: # V2 позволяет указать автора в данных if 'author' in serializer.validated_data: serializer.save() else: serializer.save(author=self.request.user)

#Deprecated версии

Пометьте старую версию как устаревшую:

from rest_framework.response import Response from rest_framework import status class ArticleViewSet(viewsets.ModelViewSet): def get_queryset(self): version = self.request.version if version == 'v1': # Предупреждение о депрекации from rest_framework.exceptions import APIException if version == 'v1': # Возвращаем предупреждение в заголовке self.headers = { 'Deprecation': 'true', 'Sunset': '2024-12-31', # Дата удаления версии } return Article.objects.all()

Заголовки ответа:

Deprecation: true Sunset: Sun, 31 Dec 2024 23:59:59 GMT

#Best Practices

  1. Всегда используйте версионирование для публичных API
  2. URLPathVersioning — самый популярный и понятный выбор
  3. Документируйте версии — укажите, что изменилось в каждой версии
  4. Поддерживайте минимум 2 версии — дайте время на миграцию
  5. Используйте разные сериализаторы для разных версий
  6. Предупреждайте о депрекации — заголовки Deprecation, Sunset
  7. Установите дату удаления старой версии (Sunset)

Далее: Кастомизация ответов