Schema Generation in Django Rest Framework 3.5
While previous versions of Django Rest Framework contained schema generation, in 3.5 the feature is front and center. Among several bug fixes, a couple of critical things have been added.
- Docstrings on your API's views are now included in your schema's definition.
- The helper method get_schema_view() has been added.
- The schema generation code has been fully documented and outlined here.
As you'll see, this makes it simpler to document your API with inline docstrings, and quickly generate "Schema Views" for a given base url endpoint. These schema views can report your API in any way you'd like, depending on the renderer you define for it to use. You can export the documentation as JSON, YAML; really anything you want if you decide to implement your own renderer.
For instance, let's take a look at how easy it is to get swagger documentation generated from our API. Fortunately for us, the renderers have already been created in the project rest-framework-swagger.
First things first, set up a django virtual environment to work in.
mkvirtualenv virtual_env
workon virtual_env
pip install Django
pip install djangorestframework
pip install django-rest-swagger
django-admin startproject api
cd api
Be sure to update your INSTALLED_APPS. While we're in settings.py, it's also a good idea to set up DRF's authentication setting.
api/settings.py
INSTALLED_APPS = [
# [django core apps]
...
'rest_framework',
'rest_framework_swagger',
]
...
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
],
}
Before setting up the swagger documentation, we need an api for it to use. For simplicity, let's just inline a simple api endpoint at 'users/' that exposes Django's base User model.
api/urls.py
from django.conf.urls import url, include
from django.contrib.auth.models import User
from rest_framework import routers, serializers, viewsets
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'email', 'is_staff')
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
router = routers.DefaultRouter()
router.register(r'users', UserViewSet)
urlpatterns = [
url(r'^users/', include(router.urls)),
]
Now for the schema generation. As mentioned earlier, Django 3.5 ships with the 'get_schema_view' method. This method will generate a Django view for your schema. The method also allows us to pass in a 'Renderer' class. A renderer will tell the view how it should render. For example (not part of the tutorial):
from rest_framework.schemas import get_schema_view
from rest_framework.renderers import CoreJSONRenderer
schema_view = get_schema_view(
title='A Different API',
renderer_classes=[CoreJSONRenderer]
)
will render your api's generated schema as JSON (specifically, JSON following the CoreAPI specification). We're after swagger documentation though. The 'rest-framework-swagger' app we installed earlier provides two useful renderers: SwaggerUIRenderer and OpenAPIRenderer. We'll need both, as the SwaggerUIRenderer actually makes use of the rendered OpenAPI format.
api/urls.py
# existing imports
...
from rest_framework.schemas import get_schema_view
from rest_framework_swagger.renderers import SwaggerUIRenderer, OpenAPIRenderer
# existing serializer, viewset, router registrations code
...
# Create our schema's view w/ the get_schema_view() helper method. Pass in the proper Renderers for swagger
schema_view = get_schema_view(title='Users API', renderer_classes=[OpenAPIRenderer, SwaggerUIRenderer])
# Inlcude the schema view in our urls.
urlpatterns = [
url(r'^', schema_view, name="docs"),
url(r'^users/', include(router.urls)),
]
If your fire up your server using './manage.py runserver', and head over to http://localhost:8000/ , you should see something like this:
Test it out. Try clicking 'List Operations' and 'Expand Operations'. It's actually pretty cool how much this generates. We get a list of all our endpoint's verbs, example usages, and can even directly use the api in the interface by filling out some forms.
Wouldn't it be nice if we had some descriptions next to our verbs though? DRF 3.5 makes that incredibly simple by pulling your docstrings into your schema as documentation. Here's how to do it:
api/urls.py
# imports and UserSerializer
...
class UserViewSet(viewsets.ModelViewSet):
"""
retrieve:
Return a user instance.
list:
Return all users, ordered by most recently joined.
create:
Create a new user.
delete:
Remove an existing user.
partial_update:
Update one or more fields on an existing user.
update:
Update a user.
"""
queryset = User.objects.all()
serializer_class = UserSerializer
# routing
...
If you now load up your server again and check out the swagger ui, you should see this:
Django Rest Framework 3.5 is doing all the work here. Because we used the appropriate names of the methods on the ModelViewSet (list, retrieve, etc.) in our docstring, DRF has added it to our schema as a description of the verb that the method translates to (get, post, etc.).
And there you have it. You should be able to wire this in to any existing APIs you have to generate documentation so you don't have to spend as much time writing all of it. There's definitely more to it than this. Hopefully, this tutorial gave you a good introduction to generating documentation with Django Rest Framework 3.5 though. As always, it's best to check the official documentation for any further questions.