Skip to content

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é :

{
  "error_code": "ENGINE_OVERHEAT",
  "message": "La température du moteur n°2 a dépassé la norme",
  "suggested_action": "Démarrer le système de refroidissement"
}
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"
    }
  ]
}
C'est incroyablement puissant ! Vous n'avez pas besoin d'écrire de code pour la vérification des types — FastAPI et Pydantic le font pour vous.


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 champ name.
  • 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 erreur 422.
  • 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 les ValueError 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

1. Si le client envoie des données d'un type incorrect (une chaîne de caractères au lieu d'un nombre), FastAPI retournera automatiquement le statut...

2. `raise HTTPException(status_code=404)` est utilisé pour...

3. Le décorateur `@validator('field_name')` dans Pydantic est nécessaire pour :

4. Que doit faire une fonction de validation dans Pydantic si les données sont correctes ?

5. `@app.exception_handler()` permet de...


🚀 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) via HTTPException.
  • ⚙️ 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 erreur 404.
  • Essayez d'envoyer une requête POST avec launch_year sous forme de chaîne de caractères et assurez-vous de recevoir une erreur 422.

⚠️ 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.