Menu
Coddy logo textTech

Enrobage des erreurs (fmt.Errorf)

Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy. Leçon 54 sur 107.

Lorsque les erreurs traversent plusieurs couches de votre application, savoir une erreur a été générée devient crucial. La fonction fmt.Errorf de Go, avec le verbe %w, vous permet d’envelopper les erreurs, en préservant l’erreur d’origine tout en ajoutant du contexte.

L’enveloppement des erreurs crée une chaîne d’erreurs. Chaque couche peut ajouter des informations sur ce qu’elle essayait de faire lorsque l’erreur s’est produite :

func ReadConfig(filename string) error {
    data, err := os.ReadFile(filename)
    if err != nil {
        return fmt.Errorf("reading config file: %w", err)
    }
    // traiter les données...
    return nil
}

Le verbe %w est spécial. Il enveloppe l’erreur d’origine dans la nouvelle. Cela diffère de %v, qui convertit simplement l’erreur en chaîne de caractères et perd l’identité de l’erreur d’origine.

func LoadSettings() error {
    err := ReadConfig("settings.json")
    if err != nil {
        return fmt.Errorf("loading settings: %w", err)
    }
    return nil
}

Lorsque LoadSettings échoue, le message d’erreur affiche la chaîne complète : "loading settings: reading config file: open settings.json: no such file or directory". Chaque couche ajoute du contexte, ce qui facilite grandement le débogage.

L’erreur encapsulée contient toujours l’erreur d’origine. Dans la prochaine leçon, tu apprendras à désencapsuler ces erreurs et à vérifier ce qu’elles contiennent à l’aide de errors.Is() et errors.As().

challenge icon

Défi

Facile

Construisons un système de traitement des commandes qui démontre l'encapsulation des erreurs sur plusieurs niveaux. Vous allez créer une chaîne de fonctions où chaque niveau ajoute du contexte aux erreurs, ce qui facilite le suivi précis de l'origine des problèmes.

Vous organiserez votre code sur deux fichiers :

  • orders.go : créez la logique de traitement des commandes avec plusieurs niveaux qui encapsulent les erreurs à mesure qu'elles remontent.
  • Implémentez trois fonctions qui forment une chaîne de traitement :

    • ValidateItem(itemID string) error - Renvoie une erreur avec le message "item not found" si l'itemID est "INVALID", sinon renvoie nil
    • ProcessOrder(orderID, itemID string) error - Appelle ValidateItem. Si cette fonction renvoie une erreur, encapsulez-la avec le contexte : "processing order [orderID]: %w". Sinon, renvoyez nil
    • SubmitOrder(customerName, orderID, itemID string) error - Appelle ProcessOrder. Si cette fonction renvoie une erreur, encapsulez-la avec le contexte : "submitting order for [customerName]: %w". Sinon, renvoyez nil

    Chaque niveau doit utiliser fmt.Errorf avec le verbe %w pour encapsuler l'erreur du niveau inférieur et construire une chaîne de contexte.

  • main.go : lisez les détails de la commande depuis l'entrée, appelez SubmitOrder et affichez le résultat. Si une erreur survient, affichez la chaîne complète des erreurs. En cas de réussite, affichez un message de confirmation.

Les entrées suivantes seront fournies :

  • Ligne 1 : nom du client
  • Ligne 2 : ID de commande
  • Ligne 3 : ID de l'article

Affichez le résultat :

  • Si une erreur survient : Error: [full error chain]
  • En cas de réussite : Order [orderID] submitted successfully for [customerName]

Par exemple, avec Alice, ORD-123 et INVALID, votre sortie doit être :

Error: submitting order for Alice: processing order ORD-123: item not found

Remarquez comment le message d'erreur affiche la chaîne complète. Vous pouvez suivre le problème depuis la tentative de soumission de niveau supérieur, en passant par le traitement de la commande, jusqu'à l'échec réel de la validation. Chaque niveau a ajouté son propre contexte à l'aide de %w.

Et avec Bob, ORD-456 et ITEM-001, votre sortie doit être :

Order ORD-456 submitted successfully for Bob

Essayez vous-même

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Lire le nom du client
	scanner.Scan()
	customerName := scanner.Text()
	
	// Lire l'ID de commande
	scanner.Scan()
	orderID := scanner.Text()
	
	// Lire l'ID de l'article
	scanner.Scan()
	itemID := scanner.Text()
	
	// TODO: Appeler SubmitOrder avec les valeurs d'entrée
	// TODO: Si une erreur se produit, afficher : Error: [full error chain]
	// TODO: If successful, print: Order [orderID] submitted successfully for [customerName]
	
	_ = customerName
	_ = orderID
	_ = itemID
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet

Entraînez-vous par vous-même : Compilateur Go en ligne