Problem
Swagger / OpenAPI can be regarded as the de-facto standard for API documentation and sandbox for experimenting with and learning a new API. Adding this to a REST API Django project is important. The process for this integration can have some hiccups based on documentation debt and deprecated packages and these hiccups cost time. Wouldn’t it be great to have some clear step by step instructions that can be ran through smoothly and quickly (4 mins or less)
Assumptions
- A Django rest api project is already set up.
- User only needs to add the swagger / OpenAPI integration.
- Using Django 3+.
Cautionary Tale
First let me describe the journey through a pitfall that many may fall into when trying to rapidly get this up and running. The first thing you might do is do a quick google, find a guide for the integration using django-rest-swagger
package and start churning through steps, before hitting some road blocks and having to change course. This may look like your experience.
You use pip
to install django-rest-swagger
package
pip install django-rest-swagger
Update settings.py file in main Django project to load django-rest-swagger
app.
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'rest_framework.authtoken', 'rest_framework_swagger', # <-- Here 'base', 'user_api', 'obj_api', 'jac_api', 'ui', ]
Update urls.py file in main Django project to first load the get_swagger_view utility function and then add path to route to Swagger UI view.
from django.contrib import admin from django.urls import path, include from rest_framework_swagger.views import get_swagger_view # <-- Here schema_view = get_swagger_view(title='Jaseci API') urlpatterns = [ path('docs/', schema_view), # <-- Here path('admin/', admin.site.urls), path('user/', include('user_api.urls')), path('', include('jac_api.urls')), path('', include('obj_api.urls')), path('ui/', include('ui.urls')), path('ui/', include('django.contrib.auth.urls')), ]
This is where the first hiccup rears it’s head. If you try to load the docs page at this point you may get the following error.
You get an AttributeError at /docs/ 'AutoSchema' object has no attribute 'get_link'
.
To solve simply add 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema'
to the REST_FRAMEWORK
parameters.
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 100, 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema' # <-- Here }
You try to reload and run into the second Hiccup.
The issue here is that staticfiles
has been deprecated since Django 2 and completely removed for Django 3. The problem is this is not clear from a wealth of how-tos on integrating swagger and DRF on the interwebs. And though it appears there’s an effort to update django-rest-swagger
, the community appears to have moved on to drf-yasg
, not as clean a name but endorsed by the official django-rest-framework
project.
Solution
So lets go ahead and quickly integrate drf-yasg
.
Use pip
to install drf-yasg
package
pip install drf-yasg
Update settings.py file in main Django project to load drf_yasg
app.
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'rest_framework.authtoken', 'drf_yasg', # <-- Here 'base', 'user_api', 'obj_api', 'jac_api', 'ui', ]
Update urls.py file in main Django project to first load the schema_view and paths you’d like.
from django.contrib import admin from django.urls import path, re_path, include # drf_yasg code starts here 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="Jaseci API", default_version='v1', description="Welcome to the world of Jaseci", terms_of_service="https://www.jaseci.org", contact=openapi.Contact(email="jason@jaseci.org"), license=openapi.License(name="Awesome IP"), ), public=True, permission_classes=(permissions.AllowAny,), ) # ends here urlpatterns = [ re_path(r'^doc(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'), #<-- Here path('doc/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), #<-- Here path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), #<-- Here path('admin/', admin.site.urls), path('user/', include('user_api.urls')), path('', include('jac_api.urls')), path('', include('obj_api.urls')), path('ui/', include('ui.urls')), path('ui/', include('django.contrib.auth.urls')), ]
Four new paths are created here including
/spec.json
(json spec of API doc)/spec.yaml
(yaml spec of API doc)/doc
(Our nice pretty Swagger UI view of API doc)/redoc
(A pretty Redoc view of API doc)
Usage
Now we load /doc
in our browser and Viola!
Redoc also looks nice!
Limitations
Hiccups validated to present themselves when using following package versions.
Django>=3.0.3,<3.1.0 djangorestframework>=3.11.0,<3.12.0 django-rest-swagger>=2.2.0,<2.3.0
Leave a Reply
Your email is safe with us.