drf-yasg provides wrong paths to URIs - django

In my application I need to have multiple Swagger pages with grouped endpoints for multiple clients.
One of my clients (paths) supplies mobile app API, another supplies web client API. URL patterns are kept in 2 different urls.py accordingly.
I'm using drf-yasg to generate schema for my API.
To generate swagger specification for those I'm initializing 2 separate schema_views for each urls.py file like this:
from api_mobile.urls import urlpatterns as mobile_patterns
from api_web.urls import urlpatterns as web_patterns
mobile_schema_view = get_schema_view(
openapi.Info(
title="Mobile API",
default_version='v3',
),
public=True,
permission_classes=(permissions.AllowAny,),
patterns=mobile_patterns,
)
web_schema_view = get_schema_view(
openapi.Info(
title="Web API",
default_version='v1',
),
public=True,
permission_classes=(permissions.AllowAny,),
patterns=web_patterns,
)
urlpatterns = [
path(
'api/mobile/docs',
mobile_schema_view.with_ui('swagger', cache_timeout=0),
name='mobile-schema-ui'
),
path(
'api/web/docs',
web_schema_view.with_ui('swagger', cache_timeout=0),
name='web-schema-ui'
),
path('api/mobile/v3/', include('api_mobile.urls'), name='mobile_urls'),
path('api/web/v1/', include('api_web.urls'), name='web_urls'),
...
]
Where mobile_patterns and web_patterns are just a list of url patterns.
If I open http://localhost:8000/api/mobile/docs or http://localhost:8000/api/web/docs I do see correctly generated schema for both lists of patterns, yet if I try to do a request directly from swagger specification page all endpoints return 404 error – they all try to do a request to non-existing url pattern without providing full path to endpoint.
So if I do a request to any view from mobile endpoints swagger tries to do a request at
http://localhost:8000/some_mobile_url/ instead of http://localhost:8000/api/mobile/v3/some_mobile_url/
And situation is the same for another schema, swagger wrongly requests http://localhost:8000/some_web_url/ instead of using full path
http://localhost:8000/api/web/v3/some_web_url/
Obviously being able to test API directly through swagger is very important so specification itself is not enough in my case.
Is this an issue in me misconfiguring swagger itlesf or should I be somehow providing path to swagger so it prepends full path to each url accordingly?

This is working fine for us:
api_schema.py
from django.conf.urls import include, url
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
from books.api.v1.urls import urlpatterns as api_v1
API_DESCRIPTION = openapi.Info(
...
)
schema_view = get_schema_view(
info=...,
...
url='https://oursite.company.io/',
patterns=[
url('api/v1/', include(api_v1)),
],
)
books.api.v1.urls.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^books', ...),
...
]
urls.py
from ...api_schema import schema_view
...
url(r'^api/v1/', include(api_v1)),
url(r'^api/schema(?P<format>\.json|\.yaml)$',
schema_view.without_ui(cache_timeout=0),
name='api_schema_v1'),
...

Related

How to handle namespace API versioning with DRF-YASG

In my project we want to have multiple versions of same api so as to support backward compatibility.
Right now we are using drf-yasg's swagger url at
/api/doc/
While our apis are
/api/vehicle/$
/api/warehouse/
And then each of the app vehicle and ware house have their own endpoints..
Now we want to do versioning as
/api/v1/doc
/api/v2/doc
/api/v1/vehicle
/api/v2/vehicle
/api/v1/warehouse
Goal is that /v1/doc should show v1 of both vehicle and ware house while/v2/doc should show only v2 of vehicle since only vehicle app has some apis with v2....
How to achieve this
I tried adding default version v1 initially in drf settings. But that resulted in no listing being shown in swagger view
I know this is an old question, but I ran into this same issue recently and was able to resolve it like so,
in my root app urls
# myapp/urls.py
...
path('api/v1/', include('api.v1.urls'),
name='v1'),
path('api/v2/', include('api.v2.urls'),
name='v2'),
...
then I created an app specifically to handle all api routes with different versions, inside this app i have a module for each of the versions I have as well as the urls for swagger/redoc like that
api/
__init__.py
|
v1/
|
__init__.py
urls.py
v2/
|
__init__.py
urls.py
In each of the version urls, I added the urls for the specific app apis and the urls for docs like so
# app/v1/urls.py
from django.urls import path, include
from drf_yasg import openapi
from drf_yasg.views import get_schema_view
urlpatterns = [
path('app1/', include('app1.api.v1.urls'), name='app1-api-v1'),
path('app2/', include('app2.api.v1.urls'), name='app2-api-v1'),
path('app3/', include('app3.api.v1.urls'), name='app3-api-v1'),
]
schema_view = get_schema_view(openapi.Info(
title="My API",
default_version='v1',
description="My REST API documentation",
contact=openapi.Contact(email="dev#myapp.com"),
),
public=True, patterns=urlpatterns)
urlpatterns += [
path('swagger/',
schema_view.with_ui('swagger', cache_timeout=0),
name='schema-swagger-ui-v1'),
path('redoc/',
schema_view.with_ui('redoc', cache_timeout=0),
name='schema-redoc-v1'),
]
Did the same for api/v2/urls.py with the corresponding changes to the urls and naming. This way I had 2 separate urls for each of version of the api docs.
Hope this helps!

Django - Disable authenticator for specific urls in urls.py?

So I have a Django app with Swagger, but I also added a custom authenticator to every endpoint automatically with
settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'cheers.utils.authenticator.CognitoAuthentication',
),
}
urls.py
schema_view = get_schema_view(
openapi.Info(
title="Resource API",
default_version="v1",
description="A sample API for resource with DRF",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="cheersocialinc#gmail.com"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=(
permissions.AllowAny,), # Anyone have access to API documentation
)
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += ADMIN_URLS
urlpatterns += SWAGGER_URLS
How do I turn this off for swagger and admin url? The reason I'm not sure is because Swagger and admin is added to URLs it's not a view
urls.py
How do I disable automatic authentication for swagger?
Also I guess a side question would be how to disable this URL when debug is False
To disable authentication | permission on swagger urls, set permission_classes in get_schema_view like this :
urls.py
from django.urls import path
from rest_framework import permissions
from rest_framework.schemas import get_schema_view
from django.conf import settings
schema_view = get_schema_view(
openapi.Info(
title="Resource API",
default_version="v1",
description="A sample API for resource with DRF",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="your_email#yopmail.com"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=(
permissions.AllowAny, ), # Anyone have access to API documentation
)
if settings.DEBUG == False
# urlpatterns
urlpatterns = [
# Production urls only
]
else:
urlpatterns = [
# Production urls + swagger doc urls
path(
'doc/',
schema_view.with_ui('swagger', cache_timeout=0),
name='schema-swagger-ui'),
]
For Django admin without authentication follow this post.

Separate documentations for internal and external APIs (drf_yasg)

I have two set of APIs: Internals, which are used in our client applications which we develop in our team, And externals, which is used by our business partners. I want to have a single document page which by authentication, shows internals APIs to our developers, and external APIs to every other viewer. How can I do that?
I use: Django, DRF, and drf-yasg.
P.S: I know this question is very general, but I do not have any clue where to start. I only guess some settings in get_schema_view, my views, and URL patterns are needed.
You can set the urlconf parameter in the get_schema_view(...) function
from django.urls import path
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
schema_view_internal = get_schema_view(
openapi.Info(
title="Snippets API",
default_version='v1',
description="Test description",
),
public=True,
permission_classes=(permissions.AllowAny,),
urlconf="path.to.your.internal_app.urls",
)
schema_view_public = get_schema_view(
openapi.Info(
title="Snippets API",
default_version='v1',
description="Test description",
),
public=True,
permission_classes=(permissions.AllowAny,),
urlconf="path.to.your.public_app.urls",
)
urlpatterns = [
path(
'public/swagger/',
schema_view_public.with_ui('swagger', cache_timeout=0),
name='schema-swagger-ui-internal'
),
path(
'internal/swagger/',
schema_view_internal.with_ui('swagger', cache_timeout=0),
name='schema-swagger-ui-internal'
),
]
Alternatively, you can set the patterns parameter also, which accept a list of URL patterns

Django DRF Swagger: In urls.py SimpleRouter / DefaultRouter are not auto discovered by swagger docs

Django DRF Swagger docs are not showing the ModelViewSets API endpoints registered as ROUTERS (not urlpattern).
In the example below standard docs (rest_framework.documentation) are showing/documenting this "follow_up" API and swagger docs are not, total skip nothing is showing.
For urlpatterns all is good, and below code for 'this_is_showing' is being nicely documented:
from urls.py file
from rest_framework.documentation import include_docs_urls
from rest_framework.routers import SimpleRouter, DefaultRouter
from rest_framework_swagger.views import get_swagger_view
from . import views
schema_view = get_swagger_view(title=MY APP API')
router = DefaultRouter()
router.register("follow_up", views.FollowUpViewSet)
urlpatterns = [
url(r'^this_is_showing/$', views.SomeView.as_view(), name='view'),
url(r'docs/', include_docs_urls(
title='API Docs', public=True)),
url(r'^swag/', schema_view),
]
What am I missing?
django-rest-swagger==2.2.0,
djangorestframework==3.11.0
EDIT 1
django-rest-swagger Package not maintained anymore!
Moved to drf_yasg: great tool with swagger and reDocs inside.
The DRF docs suggest that if you want to get the auto-generated API list view you need to use the DefaultRouter. I wonder if the SimpleRouter lacks the introspective mechanism (or other hooks) that django-rest-swagger uses to get its information.
https://www.django-rest-framework.org/api-guide/routers/#defaultrouter
EDIT 1
The DRF-swagger docs say that their example uses the DRF example: https://django-rest-swagger.readthedocs.io/en/latest/
The DRF example uses the default router: https://github.com/encode/rest-framework-tutorial/blob/master/snippets/urls.py
EDIT 2
I believe you'll also need to include the router somewhere in your URL patterns. If you look here: https://github.com/encode/rest-framework-tutorial/blob/master/snippets/urls.py
Not only is the DefaultRouter being used, but the router that's registered is included in the URL patters:
from django.conf.urls import include, url
from rest_framework.routers import DefaultRouter
from snippets import views
# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet)
router.register(r'users', views.UserViewSet)
# The API URLs are now determined automatically by the router.
# Additionally, we include the login URLs for the browsable API.
urlpatterns = [
url(r'^', include(router.urls))
]

How can i generate static api documentation for django rest APIs?

I went through the documentation and tried to use swagger and coreapi, but both are interactive, I want the same api documentation without interaction. Is it possible?
Here you can see API documentation
https://editor.swagger.io/
but its interacting with the respective api. I want same UI and without interaction.
Oh it is really easy.
First install: django-rest-swagger==2.1.2
Add to settings: 'rest_framework_swagger'
Next make urls.py changes:
from rest_framework_swagger.renderers import SwaggerUIRenderer, OpenAPIRenderer
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework import permissions
from rest_framework.renderers import CoreJSONRenderer
from rest_framework.schemas import get_schema_view
schema_view = get_schema_view(
title='Swagger My - API documentation',
public=True,
renderer_classes=[CoreJSONRenderer, OpenAPIRenderer, SwaggerUIRenderer],
authentication_classes=[JSONWebTokenAuthentication],
permission_classes=[permissions.AllowAny]
)
urlpatterns = [
# Swagger
path('docs/', schema_view),
]
And you choose renderer_classes=[CoreJSONRenderer, OpenAPIRenderer, SwaggerUIRenderer].
This is example with JWT JSONWebTokenAuthentication for auth.