backend / fastapi
Documentation OpenAPI avancée
Explication
Ce que vous allez apprendre
- Configurer les métadonnées globales de l'application (titre, contact, tags) pour Swagger
- Enrichir un endpoint avec
summary,descriptionet des exemples de payload - Masquer un endpoint interne de la documentation publique avec
include_in_schema=False - Comprendre le rôle du document OpenAPI sous-jacent à
/openapi.json - Personnaliser la fonction de génération du schéma OpenAPI pour des besoins avancés
Dans quel contexte ?
L'équipe frontend qui consomme l'API app/main.py se plaint de devoir régulièrement demander sur Slack "à quoi ressemble le payload attendu pour créer une commande ?", faute d'exemples concrets dans la documentation Swagger générée automatiquement. Ajouter summary, description et un exemple de payload directement sur l'endpoint POST /orders élimine cet aller-retour : la documentation interactive sur /docs devient auto-suffisante pour intégrer l'API sans poser de question.
Se souvenir d'un point vu dès la leçon 1
La toute première leçon de ce cours soulignait déjà que la documentation Swagger de FastAPI est générée directement depuis le code. Elle ne peut donc jamais être "en retard" par rapport à l'implémentation réelle.
Cette leçon va plus loin : comment enrichir CETTE documentation pour qu'elle devienne vraiment utile ? Utile à une équipe frontend ou à des développeurs tiers, pas juste techniquement correcte.
Avant ça, il faut comprendre le standard qui se cache derrière Swagger : OpenAPI. Swagger UI et ReDoc ne sont que des INTERFACES visuelles pour lire un document sous-jacent standardisé.
Ce schéma OpenAPI, accessible à /openapi.json, décrit formellement chaque route, chaque paramètre, chaque schéma de donnée. Comprendre qu'il existe ce document central explique pourquoi il peut aussi être exploité par des outils tiers.
Par exemple pour générer automatiquement un client TypeScript côté frontend. Une fois ce document compris, voyons comment l'enrichir concrètement.
Ajouter une description, des examples, un summary à chaque endpoint change l'expérience de qui découvre l'API pour la première fois. Au lieu de deviner ce qu'attend un champ en lisant le code source, il le voit directement dans une interface interactive.
Une fois la documentation enrichie, il reste un besoin différent à couvrir : cacher ce qui ne doit pas être public. include_in_schema=False retire un endpoint de la documentation SANS le désactiver pour autant.
Utile pour des routes internes de debug qui existent mais ne doivent pas apparaître dans une documentation destinée à des consommateurs externes. Une distinction importante entre "exister" et "être visible".
Prérequis
Cette leçon suppose la leçon 1 déjà acquise (génération automatique de /docs) : elle explore comment enrichir cette base, pas comment l'activer.
| Élément à enrichir | Paramètre FastAPI |
|---|---|
| Titre, contact, tags globaux | FastAPI(title=..., contact=..., openapi_tags=...) |
| Résumé/description d'un endpoint | summary=..., description=... |
| Exemple de payload | Field(examples=[...]) ou openapi_examples |
| Masquer un endpoint interne | include_in_schema=False |
Pour aller plus loin, sache que FastAPI permet aussi de personnaliser le schéma généré. Pour des besoins avancés, comme documenter globalement un schéma d'authentification.
FastAPI permet de reprendre la main sur la fonction qui génère le schéma OpenAPI final. Pour l'enrichir manuellement au-delà de ce que la génération automatique produit seule.
Commandes & code
Documentation OpenAPI avancée
from fastapi import FastAPI
app = FastAPI(
title="API E-commerce",
description="API complète de gestion de produits, commandes et utilisateurs.",
version="2.1.0",
contact={"name": "Équipe Backend", "email": "backend@example.com"},
license_info={"name": "MIT"},
openapi_tags=[
{"name": "products", "description": "Gestion du catalogue produits"},
{"name": "orders", "description": "Cycle de vie des commandes"},
{"name": "auth", "description": "Authentification et gestion de session"},
],
)# Documenter un endpoint en détail — summary, description, exemples
from pydantic import BaseModel, Field
class ProductCreate(BaseModel):
name: str = Field(..., description="Nom commercial du produit", examples=["Clavier mécanique RGB"])
price: float = Field(..., gt=0, description="Prix en euros TTC", examples=[89.99])
@app.post(
"/products",
summary="Créer un nouveau produit",
description="""
Crée un produit dans le catalogue. Nécessite le rôle 'editor' ou supérieur.
Le prix doit être strictement positif. Le stock initial est à 0 par défaut,
à ajuster via l'endpoint /products/{id}/stock.
""",
response_description="Le produit créé, avec son ID généré",
tags=["products"],
)
def create_product(data: ProductCreate):
return data# Exemples multiples dans le schéma OpenAPI (via Config / json_schema_extra)
class OrderCreate(BaseModel):
product_id: int
quantity: int
model_config = {
"json_schema_extra": {
"examples": [
{"product_id": 1, "quantity": 2},
{"product_id": 5, "quantity": 1},
]
}
}# Masquer un endpoint interne de la documentation publique
@app.get("/internal/debug", include_in_schema=False)
def debug_endpoint():
return {"debug": True}
# Regrouper et personnaliser via un router dédié à l'admin, hors doc publique
admin_router = APIRouter(prefix="/admin", include_in_schema=False)# Personnaliser le schéma OpenAPI généré — ex. ajouter la sécurité JWT globalement
from fastapi.openapi.utils import get_openapi
def custom_openapi():
if app.openapi_schema:
return app.openapi_schema
openapi_schema = get_openapi(
title=app.title,
version=app.version,
description=app.description,
routes=app.routes,
)
openapi_schema["components"]["securitySchemes"] = {
"BearerAuth": {"type": "http", "scheme": "bearer", "bearerFormat": "JWT"}
}
for path in openapi_schema["paths"].values():
for operation in path.values():
operation["security"] = [{"BearerAuth": []}]
app.openapi_schema = openapi_schema
return app.openapi_schema
app.openapi = custom_openapi# Générer le client TypeScript/Python à partir du schéma OpenAPI (workflow courant en équipe)
# openapi-typescript-codegen, openapi-python-client, ou orval côté frontend
# npx openapi-typescript http://localhost:8000/openapi.json -o ./frontend/src/api/schema.tsRésumé
title,description,openapi_tagsstructurent une documentation Swagger UI claire par domaine métier.Field(description=..., examples=[...])enrichit le schéma OpenAPI directement depuis les modèles Pydantic.include_in_schema=Falsemasque des endpoints internes (debug, admin technique) de la doc publique.- Le schéma OpenAPI généré peut être exporté pour générer automatiquement des clients typés côté frontend.
Exercices pratiques
Mission : le client TypeScript généré qui ignore les routes admin
Objectif : Comprendre l'impact d'include_in_schema=False sur la génération automatique de client, et enrichir la documentation d'un endpoint consommé par une équipe externe.
Contexte
L'équipe frontend exécute npx openapi-typescript http://localhost:8000/openapi.json pour générer un client typé, comme vu dans cette leçon. Le client généré ne contient aucune des routes de admin_router, alors que ces routes répondent parfaitement quand elles sont appelées manuellement avec le bon token. Par ailleurs, l'équipe continue de demander sur Slack le format exact du payload attendu par POST /orders, qui n'a encore ni summary, ni description, ni exemple.