De l'API à la doc : Un guide pratique avec DRF Spectacular

DRF Spectacular est une bibliothèque pour Django REST framework qui génère la documentation de votre API.

Swagger

Configuration (settings.py)

Tout d'abord, vous pouvez installer la librairie avec pip :

pip install drf-spectacular

Ensuite, ajoutez à vos applications :

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'rest_framework_simplejwt',
    'drf_spectacular',
]

Toujours dans votre fichier de settings, il faut penser à ajouter la DEFAULT_SCHEMA_CLASS :

# REST_FRAMEWORK
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10,
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}

On notera que j'ai déjà paramétré la pagination, et que j'ai ajouté simple jwt pour l'auth, mais c'est un autre sujet.

Maintenant, étape facultative, j'ai ajouté un peu de personnalisation à ma documentation :

# Spectacular
SPECTACULAR_SETTINGS = {
    'TITLE': 'Todo API',
    'DESCRIPTION': 'API for Todo app',
    'VERSION': '1.0.0',
    'SERVE_INCLUDE_SCHEMA': False,
}

Ces paramètres ne sont pas obligatoires, mais ils permettent de personnaliser la documentation générée par DRF Spectacular.

Vous pouvez voir la liste des settings par défaut sur cette page ==> ici.

Ajout des urls pour la documentation

Vous pouvez ensuite ajouter les chemins pour votre schéma, et les différentes documentations :

from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView
urlpatterns = [
    path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
    # REDOC + Swagger UI, vous avez le choix ! :)
    path('api/schema/swagger-ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
    path('api/schema/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
]

Modèle de base

Pour notre exemple et comprendre la base de DRF Spectacular, nous allons créer un modèle de base :

from django.db import models


class TodoItem(models.Model):
    title = models.CharField(max_length=120)
    description = models.TextField()
    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

Comme vous pouvez le voir, je ne suis pas très créatif aujourd'hui, mais c'est largement suffisant pour comprendre le fonctionnement de DRF Spectacular.

Documentation automatique avec une vue générique

Commençons par créer une vue générique, avec un serializer :

# serializers.py
from .models import TodoItem
from rest_framework import serializers


class TodoItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = TodoItem
        fields = '__all__'
# views.py
from django_filters import rest_framework as filters
from rest_framework.generics import ListAPIView
from .serializers import TodoItemSerializer
from .models import TodoItem


class TodoItemFilter(filters.FilterSet):
    class Meta:
        model = TodoItem
        fields = ['completed']



class TodoItemListView(ListAPIView):
    serializer_class = TodoItemSerializer
    filterset_class = TodoItemFilter
    queryset = TodoItem.objects.all()

J'ai volontairement rajouté un filtre sur le champ "completed" pour vous montrer que le filtre aussi va être documenté.

On peut maintenant lancer notre serveur avec :

python manage.py runserver

Et si je me rends à l'url /api/schema/swagger-ui/ pour visualiser mon API via Swagger UI :

Interface swagger UI todo

On remarque que j'ai bien l'endpoint de ma ListAPIView. Les autres endpoints présents concernent simple JWT.

Et si je déplie mon endpoint ListAPIView :

Endpoint ListApiView

Mon endpoint est documenté !

Je peux même inspecter le schéma :

Schema ListAPIView

Il est tout à fait possible de compléter la documentation de son endpoint via le décorateur extend_schema. Nous en parlerons dans la prochaine partie.

Personnaliser la documentation de son endpoint

Après avoir vu la documentation automatique avec ListAPIView, passons à un cas plus spécifique avec APIView. C'est là que le décorateur extend_schema prend tout son sens !

J'ai créé une nouvelle vue TodoItemDetailView qui hérite d'APIView :

class TodoItemDetailView(APIView):

    def get(self, request, pk):
        try:
            todo_item = TodoItem.objects.get(pk=pk)
        except TodoItem.DoesNotExist:
            return Response({"detail": "TodoItem non trouvé"}, status=status.HTTP_404_NOT_FOUND)

        serializer = TodoItemSerializer(todo_item)
        return Response(serializer.data)

Si je retourne sur /api/schema/swagger-ui/, je remarque que la documentation n'est pas aussi complète que pour ma ListAPIView.

Swagger APIView sans décorateur

C'est normal ! Une APIView nécessite plus de configuration manuelle.

C'est maintenant que l'on va s'amuser un peu avec le décorateur extend_schema.

class TodoItemDetailView(APIView):
    @extend_schema(
        summary="Détail d'un TodoItem",
        responses={
            200: OpenApiResponse(
                response=TodoItemSerializer,
                description="TodoItem récupéré avec succès",
                examples=[
                    OpenApiExample(
                        "Tâche en cours",
                        value={
                            "id": 1,
                            "title": "Faire les courses",
                            "description": "Acheter du lait et des œufs",
                            "completed": False,
                            "created_at": "2025-02-15T00:00:00Z", 
                            "updated_at": "2025-02-15T00:00:00Z"
                        },
                    ),
                    OpenApiExample(
                        "Tâche terminée",
                        value={
                            "id": 2,
                            "title": "Appeler le médecin",
                            "description": "Rendez-vous pris pour lundi",
                            "completed": True,
                            "created_at": "2025-02-14T10:00:00Z",
                            "updated_at": "2025-02-15T15:30:00Z"
                        },
                    )
                ]
            ),
            404: OpenApiResponse(
                description="TodoItem non trouvé"
            ),
        },
    )
    def get(self, request, pk):
        try:
            todo_item = TodoItem.objects.get(pk=pk)
        except TodoItem.DoesNotExist:
            return Response({"detail": "TodoItem non trouvé"}, status=status.HTTP_404_NOT_FOUND)

        serializer = TodoItemSerializer(todo_item)
        return Response(serializer.data)

Retournons sur notre Swagger :

Swagger APIView avec décorateur

Ici j'ai :

  • Un résumé de l'endpoint,
  • Des exemples concrets avec une tâche en cours et une tâche terminée,
  • La documentation des cas d'erreur possibles.

On voit dans Swagger que les exemples sont directement testables via l'interface, ce qui facilite la compréhension de l'API pour les développeurs qui vont l'utiliser.

Conclusion

Nous avons abordé les bases de DRF Spectacular à travers plusieurs aspects :

  1. La configuration initiale dans Django,
  2. La documentation automatique avec les vues génériques,
  3. La personnalisation avec le décorateur @extend_schema.

DRF Spectacular propose de nombreuses autres fonctionnalités avancées. Par exemple, la documentation des SerializerMethodField dans les serializers, j'en parle dans ce thread : https://x.com/GabrielTrouve/status/1884719269289537761

Retour au blog