Chapitre 3.6 : Gestion des erreurs et validation
Temps d'étude : 50 minutes
1. Gestion des erreurs : les "boucliers d'urgence" du vaisseau spatial
Même sur le vaisseau le plus sophistiqué, des situations imprévues peuvent survenir :
- Commande incorrecte du Centre de contrôle de mission : Le client a envoyé des données incorrectes.
- Perte de connexion avec le module : La ressource n'a pas été trouvée dans la base de données.
- Défaillance du réacteur : Erreur interne du serveur.
Une bonne gestion des erreurs est un système de "boucliers d'urgence". Elle empêche le vaisseau de se désintégrer et envoie plutôt un signal clair au Centre de contrôle de mission indiquant ce qui n'a pas fonctionné.
💡 Analogie spatiale :
Au lieu de simplement transmettre le signal "URGENCE !" au Centre de contrôle de mission, un bon ordinateur de bord enverra un rapport structuré :
Cela permet aux ingénieurs sur Terre de comprendre rapidement le problème et de prendre des mesures.
2. Validation Pydantic : l'"ordinateur de bord" intégré
Nous avons déjà rencontré la magie de Pydantic. Si vous tentez de créer un vaisseau avec un type de données incorrect (par exemple, launch_year
sous forme de chaîne de caractères), FastAPI retournera automatiquement une erreur 422 Unprocessable Entity
avec une description détaillée du champ et de la raison pour laquelle la validation a échoué.
Exemple de requête vers POST /spaceships
:
{
"name": "X-Wing",
"type": "Chasseur",
"launch_year": "il y a longtemps", // <-- Type incorrect !
"status": "En service"
}
Réponse automatique de FastAPI :
{
"detail": [
{
"loc": [
"body",
"launch_year"
],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
]
}
3. Gestion "Ressource non trouvée" : l'exception HTTPException
Nous l'avons déjà utilisé dans les opérations CRUD. HTTPException
est le moyen standard pour FastAPI d'interrompre l'exécution de la requête et de renvoyer immédiatement une réponse d'erreur au client.
Rappelons le code de GET /spaceships/{ship_id}
:
# main.py
from fastapi import FastAPI, HTTPException # Assurez-vous que HTTPException est importé
# ...
@app.get("/spaceships/{ship_id}", response_model=Spaceship, tags=["Vaisseaux spatiaux"])
def get_spaceship(ship_id: int):
ship = db_spaceships.get(ship_id)
if not ship:
# Si le vaisseau n'est pas trouvé, nous "levons" une exception 404
raise HTTPException(status_code=404, detail=f"Vaisseau spatial avec l'ID {ship_id} non trouvé")
return ship
raise HTTPException(...)
: Cet appel arrête l'exécution de la fonction.status_code=404
: Définit le statut HTTP de la réponse.detail
: Le message qui sera envoyé au client dans le corps de la réponse JSON.
4. Validateurs personnalisés : "Vérifications spéciales" avant le lancement
Et si nous voulions ajouter notre propre logique métier, plus complexe ? Par exemple, interdire de lancer des vaisseaux nommés "Étoile de la Mort".
Pour cela, Pydantic dispose d'un outil puissant : les validateurs.
Étape 1 : Ajout d'un validateur au modèle SpaceshipCreate
# main.py
from pydantic import BaseModel, Field, validator
class SpaceshipCreate(BaseModel):
name: str = Field(..., min_length=3, max_length=50)
type: str
launch_year: int = Field(..., gt=1950)
status: str
@validator('name')
def name_must_not_be_forbidden(cls, v):
"""Vérifie que le nom du vaisseau n'est pas dans la liste des noms interdits."""
if 'Death Star' in v:
raise ValueError('Les noms comme "Étoile de la Mort" sont interdits par décret Impérial !')
return v.title() # Met le nom en majuscule par la même occasion
@validator('name')
: Un décorateur qui "lie" cette fonction au champname
.cls, v
: La méthode reçoit la classe elle-même (cls
) et la valeur du champ (v
).raise ValueError(...)
: Si la validation échoue, nous levons une exception Python standard. FastAPI l'interceptera et la transformera en une belle erreur422
.return v.title()
: Si tout est bon, nous devons impérativement retourner la valeur. Nous pouvons même la modifier à la volée (par exemple, la mettre sous une forme standardisée).
Étape 2 : Test
Redémarrez uvicorn
et essayez de créer un vaisseau avec un nom interdit via /docs
. Vous obtiendrez une erreur 422
avec votre message personnalisé !
5. Gestion globale des erreurs : le "protocole d'urgence" de la station
Parfois, il est nécessaire d'intercepter des erreurs inattendues (par exemple, une panne de connexion à une base de données réelle) et de renvoyer un format de réponse unique et standardisé.
Pour cela, le décorateur @app.exception_handler
est utilisé.
Exemple : Interception de toutes les erreurs ValueError
# main.py
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
# ...
@app.exception_handler(ValueError)
async def value_error_exception_handler(request: Request, exc: ValueError):
"""
Gestionnaire global pour toutes les erreurs ValueError,
afin de renvoyer un JSON standardisé.
"""
return JSONResponse(
status_code=400,
content={"message": f"Erreur dans les données : {str(exc)}"},
)
@app.exception_handler(ValueError)
: Indique à FastAPI que cette fonction doit gérer toutes lesValueError
qui n'ont pas été interceptées précédemment.async def ...
: Les gestionnaires d'exceptions doivent être asynchrones (async
).JSONResponse
: Permet de contrôler entièrement le corps et le statut de la réponse.
Maintenant, lorsque notre validateur personnalisé se déclenchera, la réponse aura le format plus convivial que nous avons défini.
Quiz pour consolider les connaissances
🚀 Résumé du chapitre :
Vous avez installé sur votre vaisseau API un puissant système de défense et des protocoles d'urgence. Il est désormais capable de :
- 🛡️ Repousser automatiquement les attaques de "données incorrectes" à l'aide de Pydantic.
- 🚨 Signaler intelligemment l'absence de ressources (
404 Not Found
) viaHTTPException
. - ⚙️ Effectuer des "vérifications spéciales" à l'aide de validateurs personnalisés.
- 🧯 Intercepter globalement les pannes imprévues et fournir des réponses standardisées.
Votre "hyperpropulsion" est non seulement rapide, mais aussi incroyablement fiable !
📌 Vérification :
- Essayez de créer un vaisseau nommé "Étoile de la Mort" et assurez-vous de recevoir une erreur
400
avec votre message personnalisé.- Essayez de requêter
GET /spaceships/999
et assurez-vous de recevoir une erreur404
.- Essayez d'envoyer une requête
POST
aveclaunch_year
sous forme de chaîne de caractères et assurez-vous de recevoir une erreur422
.⚠️ En cas d'erreurs :
- Assurez-vous que tous les modules nécessaires (
HTTPException
,validator
,Request
,JSONResponse
) sont importés.- Vérifiez que les décorateurs
@validator
et@app.exception_handler
sont écrits sans fautes de frappe.
Félicitations pour la fin du Chapitre 3 ! Vous avez construit et lancé un API puissant, documenté et sécurisé avec FastAPI, à partir de zéro. Vous êtes prêt pour de véritables missions spatiales.