Closed phihag closed 6 years ago
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
Great job you guys are doing on this I must confess,
Assuming I have a URL api.example.com/users/login
, and the prefix /login
is just one of many in the users app
In the root url.py file we have something like:
urlpatterns = [
path('admin/', admin.site.urls),
# urls for the user on-boarding and user related functions
path('users/', include('users.api.urls')),
path('podcasts/', include('podcast.api.urls')),
path('audiostream/', include('audiostreaming.api.urls')),]
in the users app we have something like:
from users.api.views import (signup_user_api, login_api,
email_verification_request, login_api,
logout_api, activate_api, subscribe, unsubscribe
)
app_name = 'users'
urlpatterns = [
path('signup', signup_user_api, name='signup_user_api'),
path('login', login_api, name='login_api'),]
so each app URL is routed to it in the fashion above, when using the URL parameter in the _get_schemaview it doesn't display the full path with the prefix as I supply, it trims off the path component, and using the FORCE_SCRIPT_NAME solution won't work here as it would affect the whole project and changing the URL structure would cause a lot of breaking changes, so I was wondering if it would be possible to add a means of stating what URL the documentation would use on an individual app basis just as it's supplied to it
currently the URL produced is api.example.co/login
ommiting the /users
path component
if there's a way you would recommend that won't cause breaking changes I would be very much open to it
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, )
Please can you help me.
I want to prepend /v1/
to all the URLs in schema.
how can I do that.
@mohitbestpeers I dont know if you have figured out how to do this yet but adapting from the answer given by @alissonmuller what I did was to create a helper function somewhere, in my case i have a utilities file,
#utilities.py
from drf_yasg.generators import OpenAPISchemaGenerator
def my_custom_openapi_schema_generator(path_prefix:str):
if not isinstance(path_prefix, str):
raise TypeError('The supplied path_prefix must be of type str')
class CustomOpenAPISchemaGenerator(OpenAPISchemaGenerator):
def get_schema(self, *args, **kwargs):
schema = super().get_schema(*args, **kwargs)
schema.basePath = path_prefix # API prefix
return schema
return CustomOpenAPISchemaGenerator
Then you can use this as I have done in any of your urls and specify the path_prefix you want for the urls in that file or so
#urls.py
from utilities import my_custom_openapi_schema_generator
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
custom_generator_class = my_custom_openapi_schema_generator(path_prefix='/user')
schema_view = get_schema_view(
openapi.Info(
title="Users API",
default_version='v1',
description='This is the official documentation for all userAPIs',
),
generator_class=custom_generator_class,
url= f'{API_BASE_URL}',
urlconf='users.api.urls',
)
Currently, the documentation states that in order to set an API prefix, one should set the Django option
FORCE_SCRIPT_NAME
. ButFORCE_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:
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 ashttps://api.prod.example.net/v2/
and the route as/auth/login
. How do I do that with drf_yasg?