Dica 46 - DRF: drf-yasg - Yet another Swagger generator
Versões usadas no vídeo: Django 3.2.6, Django REST framework 3.12.4, drf-yasg 1.20.0 e Python 3.9.6.
Github: https://github.com/rg3915/drf-example
Doc: https://drf-yasg.readthedocs.io/en/stable/
Doc: https://github.com/axnsan12/drf-yasg/
drf-yasg é uma outra biblioteca para gerar a documentação com Swagger e reDoc.
O nome é um acrônimo de Yet Another Swagger Generator. Ela lê as rotas, viewsets e serializers do Django REST framework e gera a especificação OpenAPI (Swagger 2.0) da API, com duas interfaces prontas: o Swagger UI, onde dá para testar cada endpoint direto no navegador, e o ReDoc, uma página de documentação. A própria documentação do Django REST framework, na seção de schemas, a recomenda como pacote de terceiros.
Neste tutorial vamos acrescentar o drf-yasg ao projeto da Dica 45.
Pré-requisitos
O projeto é o do repositório drf-example, criado na dica anterior com o dr_scaffold: um projeto backend com os apps blog, product e ecommerce. Se ainda não tem, clone e rode o projeto:
git clone https://github.com/rg3915/drf-example.git
cd drf-example
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install python-decouple
python contrib/env_gen.py
python manage.py migrate
O contrib/env_gen.py gera o arquivo .env com a SECRET_KEY, que o settings.py lê com o python-decouple.
Instalando
pip install -U drf-yasg
pip freeze | grep drf-yasg >> requirements.txt
O pip freeze | grep drf-yasg mostra drf-yasg==1.20.0, e o >> acrescenta essa linha no final do requirements.txt, que fica assim:
# requirements.txt
Django==3.2.6
djangorestframework==3.12.4
dr-scaffold==1.4.3
drf-yasg==1.20.0
Configurando o settings.py
O drf-yasg precisa do django.contrib.staticfiles, que serve os arquivos CSS e JavaScript da interface do Swagger. Ele já vem no projeto. Basta acrescentar o drf_yasg:
# backend/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles', # required for serving swagger ui's css/js files
# 3rd apps
'rest_framework',
'dr_scaffold',
'drf_yasg',
# my apps
'blog',
'product',
'ecommerce',
]
Configurando o urls.py
O código abaixo vem do Quickstart da documentação do drf-yasg. O get_schema_view cria a view que gera o schema, com as informações que aparecem no topo da documentação (título, versão, descrição, termos de uso, contato e licença). O public=True inclui todos os endpoints, independente do usuário logado, e o AllowAny deixa qualquer um ver a documentação.
Como o nosso urls.py já tinha um urlpatterns, as rotas do Swagger entram num segundo bloco, concatenado com +=:
# backend/urls.py
from django.conf.urls import url
from django.contrib import admin
from django.urls import include, path
from drf_yasg import openapi
from drf_yasg.views import get_schema_view
from rest_framework import permissions
schema_view = get_schema_view(
openapi.Info(
title="Snippets API",
default_version='v1',
description="Test description",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="contact@snippets.local"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=(permissions.AllowAny,),
)
urlpatterns = [
path('blog/', include('blog.urls')),
path('product/', include('product.urls')),
path('ecommerce/', include('ecommerce.urls')),
path('admin/', admin.site.urls),
]
# swagger
urlpatterns += [
url(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'), # noqa E501
url(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), # noqa E501
url(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), # noqa E501
]
As três rotas:
swagger.jsoneswagger.yaml: o schema puro, sem interface, em JSON ou YAML;swagger/: a interface do Swagger UI;redoc/: a interface do ReDoc.
O # noqa E501 só serve para o linter não reclamar das linhas longas.
Para trocar o título "Snippets API" e os demais dados de exemplo pelos do seu projeto, edite o openapi.Info.
Rodando
python manage.py migrate
python manage.py runserver
Abra http://localhost:8000/swagger/. A página mostra o título "Snippets API" com a versão v1, a descrição, os links de termos de uso e de contato, a licença e, abaixo, todos os endpoints agrupados por app: blog, ecommerce e product. Cada endpoint mostra o método (GET, POST, PUT, PATCH, DELETE), a rota e o nome da operação, por exemplo GET /blog/authors/ blog_authors_list e POST /blog/authors/ blog_authors_create.
Para testar, abra POST /blog/authors/, clique em Try it out, preencha o corpo da requisição e clique em Execute:
{
"name": "Luciano Ramalho"
}
A resposta é 201 Created. Depois, em GET /blog/authors/, Try it out e Execute listam os autores cadastrados, já com o novo.
Em http://localhost:8000/redoc/ fica a mesma documentação no formato do ReDoc: o menu lateral com os grupos blog, ecommerce e product, cada operação com o schema do corpo da requisição (por exemplo, name: string, até 255 caracteres, nullable), os códigos de resposta e exemplos de payload. O botão Download baixa a especificação OpenAPI.
E http://localhost:8000/swagger.json devolve o schema em JSON, útil para gerar clientes da API automaticamente.
Observação: o django.conf.urls.url() foi removido no Django 4.0. Em versões mais novas, use re_path (de django.urls) no lugar de url, com as mesmas expressões regulares.