22 points par lemonmint 2025-06-02 | 5 commentaires | Partager sur WhatsApp

Le traitement des erreurs est souvent une partie fastidieuse lors du développement d’une API HTTP. À mesure que le nombre d’API augmente et que la logique interne se complexifie, des difficultés apparaissent sous trois aspects.

  • Retourner des codes d’erreur appropriés : pour les développeurs moins expérimentés, il est difficile d’utiliser des codes de statut HTTP cohérents dans une logique complexe.
  • Écrire un grand volume de logs de résultat : consigner des logs à tous les points de sortie attendus lorsqu’une erreur survient augmente la quantité de code et complique sa gestion.
  • Envoyer des messages d’erreur clairs : transmettre simplement un message d’erreur au client ne suffit pas pour comprendre et traiter clairement l’erreur.

Améliorer le retour de codes d’erreur appropriés

Pour résoudre le problème de cohérence dans l’utilisation des codes d’erreur, il est proposé d’implémenter une interface ou une structure HttpError incluant StatusCode et Message.

  • Solution :
    • Définir le type HttpError : encapsule le code de statut HTTP et le message.
    • Fournir des fonctions utilitaires : utiliser des fonctions utilitaires qui retournent un code d’erreur spécifique, comme httperror.BadRequest("wrong format"), afin de créer facilement des objets d’erreur.
  • Avantages :
    • Saisir les codes d’erreur et messages de manière pratique et fiable grâce à l’autocomplétion de l’IDE.
    • Réduire le risque d’erreur par rapport à la saisie manuelle de codes numériques.
    • Réduire la contrainte de devoir vérifier à chaque fois la documentation de conception préparée à l’avance.

Centraliser l’écriture des logs

Pour réduire l’écriture répétitive de logs et gérer la logique de traitement des erreurs en un seul endroit, il est proposé d’utiliser une approche consistant à envelopper le gestionnaire HTTP.

  • Solution :
    • Implémenter un routeur personnalisé (chiwrap.Router) : intégrer en interne un routeur existant comme chi.Router et y ajouter la logique de traitement des erreurs.
    • Envelopper le handler : les méthodes du routeur personnalisé comme Get reçoivent un HandlerFunc, l’exécutent en interne, puis transmettent l’erreur à une logique de traitement centralisée si elle se produit.
    • Fonction de callback d’erreur : lors de la création avec NewRouter, recevoir une fonction errCallback et l’appeler en cas d’erreur afin d’enregistrer les logs de façon centralisée ou d’effectuer un traitement supplémentaire.
  • Avantages :
    • Lorsqu’une erreur survient dans la logique de l’API, un code d’erreur et un message appropriés sont automatiquement renvoyés dans la réponse.
    • La gestion des logs est facilitée en enregistrant une fonction de callback permettant d’écrire des logs adaptés à chaque service.
    • Réduire la duplication de code et améliorer la maintenabilité.

Envoyer des messages d’erreur clairs (avec RFC7807)

Pour permettre au client de comprendre et de traiter plus clairement les erreurs, il est proposé d’envoyer des messages d’erreur structurés en s’appuyant sur le standard RFC7807.

  • Éléments clés de RFC7807 :
    • type : URI identifiant le type d’erreur (ex. : https://example.com/errors/validation).
    • title : courte description de l’erreur en une ligne.
    • status : identique au code de statut HTTP.
    • detail : description détaillée de l’erreur, lisible par un humain.
    • instance : URI spécifique où l’erreur s’est produite (ex. : /api/users/abc).
    • extensions : objet JSON contenant des informations supplémentaires (ex. : invalid_field, expected_format).
  • Implémentation :
    • Créer une structure RFC7807Error et y inclure les principaux éléments.

    • Générer facilement des objets d’erreur structurés via un modèle de chaînage de méthodes (WithType(), WithInstance(), WithExtension()).

    • Convertir RFC7807Error en HttpError via la méthode ToHttpError() afin de l’intégrer au routeur centralisé.

    • Le client peut identifier clairement le type d’erreur, sa cause et l’endroit où elle s’est produite.

    • L’efficacité du développement côté client est améliorée grâce à des réponses API plus cohérentes et plus utiles.

5 commentaires

 
aer0700 2025-06-02

Merci pour cet excellent article.

 
beoks 2025-06-02

Merci pour cet excellent article !
À titre d’information, dans Spring, il existe une implémentation dans la bibliothèque spirng-web > org.springframework.http.ProblemDetail !

 
honglu 2025-06-02

Merci pour cette bonne introduction !
Après vérification, il a été remplacé par la RFC 9457.

https://datatracker.ietf.org/doc/html/rfc9457
(document 7807 d’origine : https://datatracker.ietf.org/doc/html/rfc7807)

 
findnamo 2025-06-02

Principales différences entre la RFC 7807 et la RFC 9457

  • Gestion des types de problème : la 7807 ne permet que des URI personnalisées, la 9457 introduit un registre partagé de l’IANA
  • Gestion des erreurs multiples : la 7807 recommande l’utilisation du code d’état HTTP 207, la 9457 regroupe les erreurs liées au sein d’un même type de problème via un tableau errors
  • Champs d’extension : la 7807 permet d’ajouter des champs arbitraires, la 9457 associe explicitement les champs attendus à chaque type de problème
  • Recommandations de sécurité : absentes dans la 7807, la 9457 ajoute des directives explicites pour prévenir les vulnérabilités de sécurité
  • Pointeur JSON : non pris en charge par la 7807, la 9457 prend officiellement en charge le champ pointer

Pour les nouveaux projets depuis juillet 2023, il est recommandé d’appliquer la RFC 9457

 
honglu 2025-06-02

Il semble recommandé de définir le champ type comme une URI déréférençable.

Pour un service interne, le remplacer par un lien vers la documentation Swagger UI semble également acceptable.