Currently, the documentation states that in order to set an API prefix, one should set the Django option FORCE_SCRIPT_NAME. But FORCE_SCRIPT_NAME has huge implications on the rest of the project and is thus not an option for larger projects. It is also a classic case of using a global setting to fix a local problem, which should be avoided at all costs.
There should be a way to set a prefix just for one swaggerized API, and not for the whole project.
For reference, I have a project whose URL structure is like this:
# service/myservice/urls/api.py
urlpatterns = [
# ...
url(r'^v2/', include(api2.urlpatterns)),
]
# service/myservice/urls/api2.py
urlpatterns = [
url(r'^auth/login$', api2.login, name='api2_auth_login'),
url(r'^user$', api2.user, name='api2_user'),
url(r'^doc(?P<format>\.json|\.yaml)$', api2.schema_view.without_ui(cache_timeout=0), name='schema-json'),
url(r'^doc/$', api2.schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
]
We are using django-hosts to support multiple hostnames, but the service.myservice.urls.api is the root url configuration for the current endpoint.
Thus, a typical URL would be https://api.prod.example.net/v2/auth/login. In swagger, I want to show the base URL as https://api.prod.example.net/v2/ and the route as /auth/login. How do I do that with drf_yasg?
Thus, a typical URL would be https://api.prod.example.net/v2/auth/login. In swagger, I want to show the base URL as https://api.prod.example.net/v2/ and the route as /auth/login. How do I do that with drf_yasg?
I don't understand. Doesn't that happen by default?
I forgot one more piece of the problem: I'm passing in
urlconf='service.myservice.urls.api2',
to get_schema_view. Hence, when the path is determined, it's just the local component after /v2/, e.g. just '/auth/login'.
But that means just modifying my urlconf so that the total route is defined in service.myservice.urls.api2
# service/myservice/urls/api.py
urlpatterns = [
# ...
] + api2.url_patterns
# service/myservice/urls/api2.py
api2_urlpatterns = [
url(r'^auth/login$', api2.login, name='api2_auth_login'),
url(r'^user$', api2.user, name='api2_user'),
url(r'^doc(?P<format>\.json|\.yaml)$', api2.schema_view.without_ui(cache_timeout=0), name='schema-json'),
url(r'^doc/$', api2.schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
]
urlpatterns = [url(r'^v2/', include(api2_urlpatterns)]
solves the problem for me.
Although I think that having the ability to add a prefix - preferably simply by adding a path to the base URL - is a good idea in general, and would be necessary in a more complicated setup than mine, this is a valid workaround I can employ, and I am thus clothing this issue.
Thanks for your help!
Although I think that having the ability to add a prefix - preferably simply by adding a path to the base URL - is a good idea in general, and would be necessary in a more complicated setup than mine
The full request path in Django is always determined by SCRIPT_NAME (external path prefix outside of Django's control, e.g. reverse proxies) plus the full Django route. This was the reasoning behind giving no such "force" mechanism in drf-yasg, since there is already a "force" mechanism in Django for external paths (FORCE_SCRIPT_NAME), and full internal routes are always available to be passed into the schema view at an appropriate location.
I might reconsider this if someone provides an example of such a setup where passing full urlpatterns is not possible or desirable, but for now I would consider the implicit mechanisms sufficient.
Alternatively, you can override get_schema in a custom generator, and set the basePath attribute:
from drf_yasg.generators import OpenAPISchemaGenerator
class CustomOpenAPISchemaGenerator(OpenAPISchemaGenerator):
def get_schema(self, *args, **kwargs):
schema = super().get_schema(*args, **kwargs)
schema.basePath = '/v2' # API prefix
return schema
schema_view = get_schema_view(
... other arguments ...
generator_class=CustomOpenAPISchemaGenerator,
)
Thanks
Most helpful comment
Alternatively, you can override get_schema in a custom generator, and set the
basePathattribute: