Drf-yasg doesn't include the "api/" portion of the urls
I'm using drf-yasg to generate a Swagger schema, but it removes the "api/" portion of the url.
schema_view = get_schema_view(
openapi.Info(
title="My API",
default_version='v1',
description="...",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="hello@mycompany.com"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=[permissions.AllowAny],
)
router = routers.DefaultRouter()
router.register(r'spaces', SpacesViewSet, basename='spaces')
urlpatterns = [
url(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
url(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
path('api/', include(router.urls)),
path('api/search-options', SearchPlacesOptionsView.as_view()),
]
As you can see for the routes from the drf router, it doesn't include the /api portion of the url. However for the regular api/search-options endpoint it removes the /api portion as well, so I don't think it has something to do with the router.
I had the same question and saw no one answer to this question, so I fixed it and I'm gonna share it with you I guess this issue happened because they had plenty of changes in their package(drf_yasg).
You should override get_paths() method of OpenAPISchemaGenerator and have some changes on it,
original OpenAPISchemaGenerator in drf_yasg class:
class OpenAPISchemaGenerator(object):
# other methods ...
def get_paths(self, endpoints, components, request, public):
"""Generate the Swagger Paths for the API from the given endpoints.
:param dict endpoints: endpoints as returned by get_endpoints
:param ReferenceResolver components: resolver/container for Swagger References
:param Request request: the request made against the schema view; can be None
:param bool public: if True, all endpoints are included regardless of access through `request`
:returns: the :class:`.Paths` object and the longest common path prefix, as a 2-tuple
:rtype: tuple[openapi.Paths,str]
"""
if not endpoints:
return openapi.Paths(paths={}), ''
prefix = self.determine_path_prefix(list(endpoints.keys())) or ''
assert '{' not in prefix, "base path cannot be templated in swagger 2.0"
paths = OrderedDict()
for path, (view_cls, methods) in sorted(endpoints.items()):
operations = {}
for method, view in methods:
if not self.should_include_endpoint(path, method, view, public):
continue
operation = self.get_operation(view, path, prefix, method, components, request)
if operation is not None:
operations[method.lower()] = operation
if operations:
# since the common prefix is used as the API basePath, it must be stripped
# from individual paths when writing them into the swagger document
path_suffix = path[len(prefix):]
if not path_suffix.startswith('/'):
path_suffix = '/' + path_suffix
paths[path_suffix] = self.get_path_item(path, view_cls, operations)
return self.get_paths_object(paths), prefix
override OpenAPISchemaGenerator in my application CustomizedOpenAPISchemaGenerator class:
from collections import OrderedDict
from drf_yasg import openapi
from drf_yasg.generators import OpenAPISchemaGenerator
class CustomizedOpenAPISchemaGenerator(OpenAPISchemaGenerator):
def get_paths(self, endpoints, components, request, public):
if not endpoints:
return openapi.Paths(paths={}), ''
prefix = self.determine_path_prefix(list(endpoints.keys())) or ''
assert '{' not in prefix, "base path cannot be templated in swagger 2.0"
paths = OrderedDict()
for path, (view_cls, methods) in sorted(endpoints.items()):
operations = {}
for method, view in methods:
if not self.should_include_endpoint(path, method, view, public):
continue
operation = self.get_operation(view, path, prefix, method, components, request)
if operation is not None:
operations[method.lower()] = operation
if operations:
path_suffix = path[len(prefix):]
if not path_suffix.startswith('/'):
path_suffix = '/' + path_suffix
paths[path] = self.get_path_item(path, view_cls, operations)
# Only override this above line of upper level class paths[path_suffix] = ... to paths[path] = ...
return self.get_paths_object(paths), prefix
I only replace this:
paths[path_suffix] = self.get_path_item(path, view_cls, operations)
with this:
paths[path] = self.get_path_item(path, view_cls, operations)
After that you should path this new generator class to your swagger config, to do this you have two options:
1: Use django settings file:
SWAGGER_SETTINGS = {
'DEFAULT_GENERATOR_CLASS': 'path.to.CustomizedOpenAPISchemaGenerator',
}
- path generator_class argument in get_schema_view() function:
schema_view = get_schema_view(
# your other data
generator_class=path.to.CustomizedOpenAPISchemaGenerator
)
