Drf-yasg: Add a way to specify common API path prefix

Created on 16 Jun 2018  路  5Comments  路  Source: axnsan12/drf-yasg

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?

wontfix

Most helpful comment

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,
)

All 5 comments

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

gertjanol picture gertjanol  路  5Comments

nicholasgcoles picture nicholasgcoles  路  4Comments

jaumard picture jaumard  路  5Comments

mkurnikov picture mkurnikov  路  3Comments

maikotz picture maikotz  路  4Comments