Как исключить путь к маршрутизатору 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/ на всех конечных точках.
У меня, похоже, есть два варианта:
- Я мог бы пойти в мой urls.py и использовать
path('', include('myapp_api.urls'))
вместоpath('api/', include('myapp_api.urls'))
, но это нежелательно, потому что префикс, кажется, имеет смысл в данном контексте. - Я мог бы использовать хук предварительной обработки 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/
.
Это в сочетании с именованием файлов по версиям облегчит удаление устаревших версий и добавление новых без необходимости переименовывать импорты и т.д.