Menu
Coddy logo textTech

Error Wrapping (fmt.Errorf)

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

Lorsque des erreurs traversent plusieurs couches de votre application, savoir une erreur a pris naissance devient crucial. La fonction fmt.Errorf de Go avec le verbe %w vous permet d'envelopper des erreurs, préservant l'erreur originale tout en ajoutant du contexte.

L'emballage d'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 à l'intérieur de la nouvelle. Ceci est différent de %v, qui convertit simplement l'erreur en une 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 rend le débogage beaucoup plus facile.

L'erreur enveloppée contient toujours l'erreur d'origine à l'intérieur. Dans la prochaine leçon, vous apprendrez comment désenvelopper ces erreurs et vérifier ce qu'elles contiennent en utilisant errors.Is() et errors.As().

challenge icon

Défi

Facile

Construisons un système de traitement des commandes qui démontre l'enveloppement d'erreurs (error wrapping) à travers plusieurs couches. Vous allez créer une chaîne de fonctions où chaque couche ajoute du contexte aux erreurs, ce qui permet de retracer facilement l'origine exacte des problèmes.

Vous organiserez votre code sur deux fichiers :

  • orders.go : Créez la logique de traitement des commandes avec plusieurs couches qui enveloppent les erreurs au fur et à mesure qu'elles remontent.

    Implémentez trois fonctions qui forment une chaîne de traitement :

    • ValidateItem(itemID string) error - Retourne une erreur avec le message "item not found" si le itemID est "INVALID", sinon retourne nil
    • ProcessOrder(orderID, itemID string) error - Appelle ValidateItem. S'il retourne une erreur, enveloppez-la avec le contexte : "processing order [orderID]: %w". Sinon, retourne nil
    • SubmitOrder(customerName, orderID, itemID string) error - Appelle ProcessOrder. S'il retourne une erreur, enveloppez-la avec le contexte : "submitting order for [customerName]: %w". Sinon, retourne nil

    Chaque couche doit utiliser fmt.Errorf avec le verbe %w pour envelopper l'erreur de la couche inférieure, construisant ainsi une chaîne de contexte.

  • main.go : Lit les détails de la commande depuis l'entrée, appelle SubmitOrder, et affiche le résultat. Si une erreur survient, affichez la chaîne d'erreur complète. En cas de succès, affichez un message de confirmation.

Les entrées suivantes seront fournies :

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

Affichez le résultat :

  • Si une erreur survient : Error: [full error chain]
  • En cas de succès : Order [orderID] submitted successfully for [customerName]

Par exemple, avec Alice, ORD-123, et INVALID, votre sortie devrait ê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 tracer le problème depuis la tentative de soumission au plus haut niveau, à travers le traitement de la commande, jusqu'à l'échec de validation réel. Chaque couche a ajouté son propre contexte en utilisant %w.

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

Order ORD-456 submitted successfully for Bob

Aide-mémoire

Utilisez fmt.Errorf avec le verbe %w pour envelopper les erreurs tout en préservant l'erreur d'origine :

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

Le verbe %w enveloppe l'erreur d'origine à l'intérieur de la nouvelle, contrairement à %v qui convertit simplement l'erreur en une chaîne de caractères et perd l'identité de l'erreur d'origine.

L'enveloppement d'erreurs crée une chaîne où chaque couche ajoute du contexte :

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

Le message d'erreur résultant affiche la chaîne complète : "loading settings: reading config file: open settings.json: no such file or directory"

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 la 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 survient, afficher : Error: [chaîne d'erreur complète]
	// TODO : En cas de succès, afficher : 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