Как исключить путь к маршрутизатору drf из настройки drf_spectacular SERVERS

Я хотел бы проверить некоторые лучшие практики при использовании drf_spectacular с проектом django.

У меня есть API в проекте django, где все конечные точки используют префикс api/, то есть в urls.py я использую.

path('api/', include('myapp_api.urls')),

В urls.py проекта myapp_api используется маршрутизатор по умолчанию, поэтому что-то вроде

router = routers.DefaultRouter()
router.register(r'assets', views.AssetsViewSet)

По умолчанию это означает, что документация swagger будет представлять все конечные точки в виде чего-то вроде...

/api/assets/{}/

вместо

/assets{}/

Это само по себе не является большой проблемой, поскольку тестовые вызовы swagger UI будут работать нормально, так как они будут правильно вызывать https://example.com/api/assets{}/. Просто в SwaggerUI это выглядит немного беспорядочно.

Основная проблема возникает, когда я устанавливаю объект сервера OpenAPI, который для drf_spectacular является настройкой SERVERS, например

SPECTACULAR_SETTINGS = {
    'SERVERS': [{'url': 'https://example.com/api'}],
}

В этот момент у меня происходит сбой, потому что тестовые вызовы Swagger будут пытаться запросить

https://example.com/api/api/assets/{}/

и будет по-прежнему показывать префикс /api/ на всех конечных точках.

У меня, похоже, есть два варианта:

  1. Я мог бы пойти в мой urls.py и использовать path('', include('myapp_api.urls')) вместо path('api/', include('myapp_api.urls')), но это нежелательно, потому что префикс, кажется, имеет смысл в данном контексте.
  2. Я мог бы использовать хук предварительной обработки drf_spectacular и подправить все конечные точки, которые он генерирует.

e.g.

SPECTACULAR_SETTINGS = {
    'SERVERS': [{'url': 'https://example.com/api'}],
    'PREPROCESSING_HOOKS': ['my_preprocessing_hooks.strip_the_api_prefix']
}


def strip_the_api_prefix(endpoints, **kwargs):
    for i in range(0, len(endpoints)):
        temp = list(endpoints[i])
        if temp[0].startswith('/api'):
            temp[0] = temp[0][4:]
        endpoints[i] = tuple(temp)
    return endpoints

Мой вопрос в том, что все это выглядит как хрупкий хак, и мне интересно, не упускаю ли я чего-то. Я хотел бы знать, следую ли я лучшим практикам и т.д.

Я почти уверен, что мне нужно установить по крайней мере одно значение OpenAPI server, поэтому сегодня это https://example.com/api, что всегда может быть "передовой", но позже может быть https://api.example.com/v1, если в будущем будет несколько основных версий, которые я хочу поддерживать. Также кажется разумным, что SwaggerUI не имеет кучи префиксов /api/ для всех конечных точек, которые генерируются из файла urls.py.

Я не использовал drf-spectacular раньше, но я бегло просмотрел документацию и, возможно, смогу дать вам несколько идей.

Для ваших урлов DRF - path('api/', include('myapp_api.urls')),. Для разных версий API у вас будут разные url файлы, даже разные файлы представлений. Например, файлы без версий, являющиеся вашим последним "кровоточащим краем":

myapp_api/urls/urls.py  # latest and greatest
myapp_api/urls/v1_urls.py  # older supported urls
myapp_api/views/views.py  # latest and greatest
myapp_api/urls/v1_views.py  # older supported urls

Затем вы импортируете различные версии в ваш основной файл url:

path('api/', include('myapp_api.urls.urls')),
path('api/v1/', include('myapp_api.urls.v1_urls')),

Для вашего drf-spectacular, Возможно, вам не нужно реализовывать SERVERS, но если нужно, то можно сделать следующее. Однако я не использовал этот пакет раньше. Вот документация , которую я просмотрел для этой настройки.

SPECTACULAR_SETTINGS = {
    'SERVERS': [
        {'url': 'https://example.com/api'},
        {'url': 'https://example.com/api/v1'},
    ],
}

Если URL и представления настроены с версионностью, то версионность будет использоваться по умолчанию. Хотя, когда вы создаете новый "передовой" API, это повлечет за собой переименование файлов и импорта. Если вы не хотите этого, альтернативная настройка может быть следующей:

Вы отслеживаете API, указывая их версии в именах файлов, где v1 - самая старая, и вы увеличиваете для каждой итерации. Таким образом, если у вас есть v1, v2 и v3, v3 будет самой последней. Это будет urls/v1_urls.py, urls/v2_urls.py и так далее. Тогда вы обновите только основной файл urls, чтобы он указывал на последнюю версию. Например:

# Older supported APIs
path('api/v1/', include('myapp_api.urls.v1_urls')),
path('api/v2/', include('myapp_api.urls.v2_urls')),

# Latest API
path('api/', include('myapp_api.urls.v3_urls')),

Если бы v4 стала последней, вы бы переместили v4 в последнюю версию, а v3 - в самую старую, и изменили бы URL на api/v3/.

Это в сочетании с именованием файлов по версиям облегчит удаление устаревших версий и добавление новых без необходимости переименовывать импорты и т.д.

Вернуться на верх