Une API c’est bien, une API bien documentée c’est indispensable ! Pour les développeurs, la documentation permet de savoir ce que l’API attend comme données ou ce qui va être fourni en réponse. Dans cet article, nous vous expliquons comment rédiger facilement les documentations de vos API Rest JSON sous Django. Cet article est a destination des développeurs ayant déjà implémenté Django 🙂

Dans cette page

Pré-requis pour rédiger une documentation d’API sur Django

Pour suivre cet article, vous devez avoir installé l’application Django avec la librairie Django rest framework. Si vous avez beaucoup de données, vous devez mettre en place une base données de type MySQL, PostgreSQL, ….

Après l’installation de Django et Dango Rest Framework, on se retrouve avec l’arborescence ci-dessous :

. ├── app │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-39.pyc │ │ ├── settings.cpython-39.pyc │ │ ├── urls.cpython-39.pyc │ │ └── wsgi.cpython-39.pyc │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── db.sqlite3 └── manage.py

Dans notre cas, nous avons créé le projet de départ de Django dans le dossier app.

Mise en place de l’API Django

Pour notre exemple, nous allons rapidement mettre en place une API sous Django.
On va faire un exemple classique de liste de tâches à faire (la fameuse TODO List :).

On va dans cette partie créer l’app, le modèle, le sérialiseur et la vue pour les tâches.

Créer un app Django

Il faut tout d’abord créer une app Django. Nous allons ici l’appeler api.

python manage.py startapp api

Le dossier api doit être créé à la racine de Django avec les fichiers ci-dessous.

api ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ └── __init__.py ├── models.py ├── tests.py └── views.py

Il faut ensuite ajouter l’app « api » à la fin de la liste des INSTALLED_APPS dans le fichier de settings (app/settings.py).

Elle est ainsi prise en compte par Django.

Créer un modèle

Les modèles sur Django servent à définir la structure de la base de données. Django fournit une liste de type de champs prédéfinis.

Nous créons un modèle pour les tâches. On va appeler notre modèle Todo. Les champs de ce modèle vont être : un titre, une description, un booléen « completed », des dates de création et de dernière mise à jour.

api/models.py
from django.db import models class Todo(models.Model): title = models.CharField(max_length=100) description = models.TextField(blank=True, null=True) completed = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) def __str__(self): return self.title

Le petit plus

Dans les modèles, la fonction __str__ vous permet de définir une représentation en chaîne de caractère d’un élément du modèle.

Créer un sérialiseur

Les sérialiseurs permettent de définir la structure des données qu’on va retourner en réponse JSON.

Ils servent à valider les données arrivant sur l’API. C’est Django Rest framework qui définit la base des sérialiseurs. Comme pour les modèles, des types de champs sont disponibles via Django Rest framework.

Les sérialiseurs peuvent être mis en lien avec un modèle. Il se base alors sur les champs du modèle et leurs types pour définir ceux du sérialiseur. C’est magique et c’est ce que nous allons utiliser.

Généralement, nous créons dans les apps un fichier serializers.py pour tous les réunir. C’est dans ce fichier que nous allons mettre le sérialiseur pour les tâches. On va l’appeler TodoSerializer.

api/serializers.py
from rest_framework import serializers from .models import Todo class TodoSerializer(serializers.ModelSerializer): class Meta: model = Todo fields = ( "id", "title", "description", "completed", "created_at", "updated_at", ) read_only_fields = ( "id", "created_at", "updated_at", )

Dans la sous-classe Meta, l’attribut model permet de lier le modèle.

Dans fields, on liste les champs à retourner dans les réponses de l’API. Les champs, dans read_only_fields, sont ceux qui ne peuvent pas être modifié via l’API. Nous pourrons le voir plus tard dans la documentation.

Créer une vue

Les vues sur Django sont les endroits où on récupère et traite les informations avant de les retourner en réponses. Il y a différentes manières de créer les vues : soit avec une fonctions, soit avec une classe.

Les vues sont à mettre dans le fichier views.py de votre app.

api/views.py
from rest_framework import viewsets from api.models import Todo from api.serializers import TodoSerializer class TodoViewSet(viewsets.ModelViewSet): queryset = Todo.objects.all() serializer_class = TodoSerializer

Nous choisissons de faire la vue sous forme de classe. Elle hérite de ModelViewSet.
ModelViewSet est une classe prédéfinie par Django Rest framework. Elle apporte toute la logique de base pour une vue en lien avec un modèle.

Cette classe nous intègre les routes suivantes :

  • index pour retourner une liste des tâches
  • create pour créer une tâche
  • retrieve pour retourner une tâche en fonction de son id
  • update et partial_update pour l’édition d’une tâche
  • destroy pour supprimer une tâche

Nous définissons dans la classe un queryset. Cela correspond aux données que nous voulons rendre accessible. Nous donnons aussi à la vue le sérialiseur qui a été créé précédemment.

Une fois que c’est fait, nous créons une url pour cette vue. Cela se passe dans le fichier urls.py. Par défaut, Django ne crée pas ce fichier dans les apps. Nous le créons donc et ajoutons l’url de notre vue.

api/urls.py
from django.urls import path, include from rest_framework.routers import DefaultRouter from . import views router = DefaultRouter() router.register("todos", views.TodoViewSet, basename="todos") urlpatterns = [ path("", include(router.urls)), ]

La classe DefaultRouter de Django Rest framework permet d’enregistrer les différentes routes du ViewSet.

Nous incluons ensuite les routes de notre app dans le fichier url.py du projet Django.

app/urls.py
from django.contrib import admin from django.urls import include, path urlpatterns = [ # ... path("api/", include("api.urls")), ]

Mettre en place la documentation

Pour la documentation de l’API, nous utilisons le package drf-spectacular. Ce package permet de rédiger la documentation d’API sur Django. Il se base sur nos vues et les sérialiseurs pour le faire. Il nous permet aussi de surcharger la documentation avec des ajouts ou des modifications.

Drf-spectacular génère la documentation en format OpenAPI 3. Il propose aussi une route sur laquelle nous pouvons lire la documentation. Pour afficher la documentation, nous avons la possibilité d’utiliser la librairie swagger ou redoc.

Installation de drf-spectacular

Pour l’installation de drf-spectacular, vous lancez la commande pip install drf-spectacular
ou ajouter drf-spectacular==<version du package> au fichier requirements.txt et demander l’installation des packages en fonction de ce fichier.

Dans le fichier settings.py, nous ajoutons drf_spectacular à la liste des INSTALLED_APPS. Nous précisons à Django Rest framework d’utiliser drf-spectacular comme générateur de schéma.

app/settings.py
# ... INSTALLED_APPS = [ # ... 'drf_spectacular', # ... ] # ... REST_FRAMEWORK = { # YOUR SETTINGS 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', }

Paramètrage de drf-spectacular

Nous configurons drf-spectacular pour donner un titre, une description ou une version à la documentation. D’autres paramètres sont disponibles dans la documentation du package.

app/settings.py
SPECTACULAR_SETTINGS = { 'TITLE': 'Todo API', 'DESCRIPTION': 'API for todo list', 'VERSION': '0.0.1', 'SERVE_INCLUDE_SCHEMA': False, # ... }

En plus

Si les routes de votre API ont un préfixe (par ex. : /v1/), drf-spectacular propose le paramètre SCHEMA_PATH_PREFIX pour le prendre en compte. Cela permet au package de mieux découper vos routes.

Ajout des urls

Pour rendre accessible la documentation, nous ajoutons les routes de drf-spectacular à Django dans le fichier urls.py de l’application api.

api/urls.py
# ... from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView # ... urlpatterns = [ # ... path("schema/", SpectacularAPIView.as_view(), name="schema"), path( "docs/", SpectacularSwaggerView.as_view( template_name="swagger-ui.html", url_name="schema" ), name="swagger-ui", ), ]

Nous créons le fichier de template pour afficher la documentation.
Dans notre cas, e fichier s’appelle swagger-ui.html et nous l’avons placé dans le dossier de template de l’app api.

api/templates/swagger-ui.html
<!DOCTYPE html> <html> <head> <title>Swagger</title> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@3/swagger-ui.css"/> </head> <body> <div id="swagger-ui"></div> <script src="https://unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"></script> <script> const ui = SwaggerUIBundle({ url: "{% url 'schema' %}", dom_id: '#swagger-ui', presets: [ SwaggerUIBundle.presets.apis, SwaggerUIBundle.SwaggerUIStandalonePreset ], layout: "BaseLayout", requestInterceptor: (request) => { request.headers['X-CSRFToken'] = "{{ csrf_token }}" return request; } }) </script> </body> </html>

Affichage de la documentation

Avec cette mise en place, vous pouvez vous rendre sur l’url de la documentation d’API sur Django.

Vous devriez avoir un résultat similaire à l’image ci-dessous.

documentation d'API sur Django
Image d’exemple de la documentation API faite avec Django

Le package drf-spectacular a automatiquement listé toutes les routes disponibles sur Django.

Si on déplie les routes, on peut voir qu’il affiche les données qu’on a configurées dans le sérialiseur.

Dans la route POST au niveau de la Request body, le package ne présente pas les champs qui sont en read-only dans notre sérialiseur.

Personnalisation de la documentation d’API sur Django

On peut surchargé la documentation en ajoutant des paramètres ou des réponses par exemple.

Pour vous montrer cela, je vais ajouter un paramètre GET à la route d’index des tâches. Ce paramètre va servir à filtrer les tâches complété. Nous ajouterons par la suite ce paramètre à drf-spectacular.

api/views.py
from rest_framework import viewsets from rest_framework.response import Response from drf_spectacular.utils import extend_schema, OpenApiParameter from api.models import Todo from api.serializers import TodoSerializer class TodoViewSet(viewsets.ModelViewSet): queryset = Todo.objects.all() serializer_class = TodoSerializer @extend_schema( parameters=[ OpenApiParameter( name="completed", description="Filter todos by completed status", type=bool, required=False, ) ] ) def list(self, request, *args, **kwargs): todos = self.get_queryset() completed = request.query_params.get("completed", None) if completed is not None: todos = todos.filter(completed=True if completed == "true" else False) serializer = self.get_serializer(todos, many=True) return Response(serializer.data)

Le décorateur extend_schema permet d’ajouter plus d’information à la documentation d’API sur Django.

Nous pouvons voir en rafraichissant la documentation que le paramètre completed a été ajouté. Le package drf-spectacular nous propose aussi les valeurs possible pour ce paramètre.

personnalisation de documentation d'API sur Django
Détail d’une route avec un paramètre GET sur la documentation API Django

Et maintenant ?

Vous disposez de développeurs heureux et votre application est plus facile à maintenir dans le temps.

On espère que vous avez apprécié ce petit partage d’expérience.

A bientôt et n’hésitez pas à nous contacter si vous avez des questions.