How to handle namespace API versioning with DRF-YASG - django

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!

Related

i am facing issue to add path to product urls.py file ,i dont know how

```
I am creating CRUD for categories I make a CategoriesViewSet.
on the other hand, I register the router as default in urls.py(Products) for viewset of categories but I don't know how to add a path into the product => urls.py and also the path I want to include into the core url.py file.
product => urls.py
router =routers.DefaultRouter()
router.register(r'categories', CategoryViewSet)
urlpatterns = [
path('list/',ProductList.as_view(),name="View Product"),
path('add/',AddProduct.as_view(),name="Create Product"),
path('<int:pk>/',ProductDetails.as_view(),name="product_detail"),
# path('categories/', CategoryViewSet.as_view({'get':'list'}))
path(r'^', include(router.urls)),
re_path(r'categories/', CategoryViewSet.as_view({'get':'list'}),
name='product-detail')
]
Core => urls.py
path('admin/', admin.site.urls),
path('api/product/', include('products.urls')),
path('api/user/', include('user.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns = format_suffix_patterns(urlpatterns)
I don't think you have a clear idea of what Routers do in Django.
From DRF's official documentation:
Some Web frameworks such as Rails provide functionality for
automatically determining how the URLs for an application should be
mapped to the logic that deals with handling incoming requests.
REST framework adds support for automatic URL routing to Django, and
provides you with a simple, quick and consistent way of wiring your
view logic to a set of URLs.
This line:
router.register(r'categories', CategoryViewSet)
according to Django REST Framework's (DRF) documentation, generates 2 URL patterns:
categories/ - Return the list of categories
categories/{pk}/ - Return category with specified primary key (pk)
You don't need to add those again in Product's urls.py. You can either only specify the router.register(...) method, or manually add them like that:
path('categories/', CategoryViewSet.as_view(), name='product-detail')
It works. In my view I implemented and it works that's why I am asking First of all we have to add the
import [re_path and include] in the Urls.py (Products)
then we have to add--------------------
~the code will be added in the urls.py(Products) below the import library.
router = routers.SimpleRouter()
router.register(r'', CategoryViewSet, 'categories')
in Url Patterns~
re_path(r'^categories/',include((router.urls,'categories'),namespace='categories'))
it works.

Swagger Django [No operations defined in spec]

I have been trying to integrate Swagger with Django Application and encounter this error:
No operations defined in spec!
My project structure is
App
views.py
urls.py
..
App2
settings.py
urls.py
..
I am using drf_yasg for my purpose. I have included all details in settings.py and in App2 I have this in urls.py:
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
schema_view = get_schema_view(
openapi.Info(
title="Testing",
default_version='v1',
description="Doc Integration",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="abc#abc.com"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=(permissions.AllowAny,),
)
urlpatterns=[path("admin/", admin.site.urls),
path("", include("app.urls")),
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
path('redoc', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),]
My class views such as (class Att(generic.TemplateView) and methods are declared in views.py under App. I tried methods such as #swagger_auto_schema, #api_view, to display app class and functions in the documentation. But it just returns No operations defined in spec!.
I tried using routers to register the view as well but did not work, even django-rest-swagger fails. Any help is appreciated. Thanks!
I have a project made of Django and I'm new to DRF. I had seen No operations defined in spec! as well while trying drf-yasg which is one of Swagger generators. Hope this way works for you.
I imported ->
from rest_framework.views import APIView
The class in views.py was like
class FeedView(View):
and the functions showed up when I changed the class like
class FeedView(APIView):
I need to deal with #swagger_auto_schema, #api_view to make my API document works with proper parameters.

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

drf-yasg provides wrong paths to URIs

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

How to generate swagger documentation for 'other' URLconfs from apps included into the project urls.py

I am working on a project using the following dependencies:
Python 3.7
django 2.2.6
djangorestframework 3.9.4
I am creating multiple apps and each of these apps has their own urls.py files which are included in the URLs file of the parent project. I wish to create swagger documentation for the API endpoints described in the included URLconf files. However, swagger only documents URLs mapped in the parent URLconf file.
I have already tried including the swagger view in the URLconfs of the projects but it still serves the parent URLconf only.
Basically, I have added the below code to all my URLconf's
from rest_framework_swagger.views import get_swagger_view
schema_view = get_swagger_view(title='Some APIs')
urlpatterns = [
path('', schema_view),
]
This did the trick:
from rest_framework.documentation import include_docs_urls
urlpatterns = [
path('docs/', include_docs_urls(title=API_TITLE, description=API_DESCRIPTION))
]