Menu
Coddy logo textTech

Rozpakowywanie za pomocą `errors.As`

Część sekcji Logika i przepływ sterowania ścieżki GO w Coddy. Lekcja 41 z 68.

O ile errors.Is pomaga identyfikować konkretne wartości błędów w łańcuchu, czasami trzeba uzyskać dostęp do rzeczywistych pól i danych niestandardowego typu błędu. Funkcja errors.As umożliwia to, znajdując pierwszy błąd w łańcuchu pasujący do określonego typu i wyodrębniając go do sprawdzenia.

Funkcja errors.As przyjmuje dwa parametry: błąd do zbadania oraz wskaźnik do zmiennej docelowego typu błędu. Jeśli znajdzie pasujący typ błędu w łańcuchu, przypisuje ten błąd do zmiennej i zwraca true:

var validationErr ValidationError
if errors.As(wrappedErr, &validationErr) {
    fmt.Printf("Field: %s, Message: %s\n", validationErr.Field, validationErr.Message)
}

Jest to szczególnie przydatne podczas pracy z niestandardowymi typami błędów, które zawierają dodatkowy kontekst. W przeciwieństwie do errors.Is, który sprawdza jedynie równość, errors.As wyodrębnia rzeczywistą instancję błędu, umożliwiając dostęp do jej pól i metod. Dzięki temu obsługa błędów w złożonych aplikacjach jest bardziej zaawansowana i dostarcza więcej informacji.

challenge icon

Wyzwanie

Łatwy

Zbuduj system obsługi błędów API, który używa errors.As do wyodrębniania i analizowania niestandardowych typów błędów z łańcuchów opakowanych błędów. To wyzwanie pokazuje, jak używać errors.As, aby uzyskać dostęp do pól i danych określonych niestandardowych typów błędów, nawet jeśli zostały opakowane dodatkowym kontekstem.

Otrzymasz dwa dane wejściowe:

  • Ciąg zawierający szczegóły żądania API w formacie "endpoint,method,error_code,error_field" (np. "/users,POST,400,email")
  • Ciąg zawierający kontekst systemu w formacie "service_name,request_id" (np. "UserAPI,req_12345")

Twoje zadanie:

  1. Utwórz niestandardowy typ błędu o nazwie APIError struct z trzema polami:
    • Code (int) - kod statusu HTTP
    • Field (string) - pole, które spowodowało błąd
    • Message (string) - opis błędu
  2. Zaimplementuj metodę Error() string dla APIError, która zwraca: "API error [code]: [message] (field: [field])"
  3. Przetwórz pierwsze dane wejściowe, dzieląc je po przecinkach, aby uzyskać endpoint, method, error code i error field
  4. Przetwórz drugie dane wejściowe, dzieląc je po przecinkach, aby uzyskać service name i request ID
  5. Przekonwertuj ciąg z kodem błędu na liczbę całkowitą
  6. Utwórz instancję APIError na podstawie kodu błędu:
    • Jeśli kod wynosi 400: message "invalid request data"
    • Jeśli kod wynosi 401: message "authentication required"
    • Jeśli kod wynosi 404: message "resource not found"
    • Jeśli kod wynosi 500: message "internal server error"
    • Dla dowolnego innego kodu: message "unknown error"
  7. Utwórz błąd opakowany na poziomie endpointu za pomocą fmt.Errorf i %w: "[method] [endpoint] failed: %w"
  8. Utwórz opakowany błąd na poziomie usługi: "[service_name] request [request_id] failed: %w"
  9. Użyj errors.As, aby wyodrębnić APIError z łańcucha opakowanych błędów i wyświetlić wynik wyodrębniania:
    • Jeśli wyodrębnianie się powiedzie: "API error extracted successfully"
    • Jeśli wyodrębnianie się nie powiedzie: "Failed to extract API error"
  10. Jeśli wyodrębnianie się powiedzie, wyświetl szczegóły wyodrębnionego błędu:
    • "Extracted Error Details:"
    • "Code: [code]"
    • "Field: [field]"
    • "Message: [message]"
    • "Full error: [full_error_message_from_Error_method]"
  11. Wyświetl cały łańcuch błędów:
    • "Error Chain:"
    • "Original: [original_api_error_message]"
    • "Endpoint level: [endpoint_level_error_message]"
    • "Service level: [service_level_error_message]"
  12. Wyświetl końcową analizę:
    • "Error Analysis:"
    • "Service: [service_name]"
    • "Request ID: [request_id]"
    • "Endpoint: [method] [endpoint]"
    • "HTTP Status: [code]"
    • "Problem Field: [field]"
    • "Error Category: [error_category]", gdzie error_category to "Client Error" dla kodów 400-499, "Server Error" dla kodów 500-599 lub "Unknown" dla innych kodów

Użyj pakietu strings, aby dzielić ciągi wejściowe po przecinkach, pakietu strconv, aby przekonwertować ciąg z kodem błędu na liczbę całkowitą, pakietu errors dla errors.As oraz pakietu fmt do opakowywania błędów. To wyzwanie pokazuje, jak errors.As umożliwia dostęp do konkretnych pól i metod niestandardowych typów błędów w opakowanych łańcuchach błędów, co pozwala na zaawansowaną obsługę i analizę błędów.

Spróbuj swoich sił

package main

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
)

func main() {
	// Wczytaj dane wejściowe
	var apiDetails string
	var systemContext string
	fmt.Scanln(&apiDetails)
	fmt.Scanln(&systemContext)
	
	// Przeanalizuj dane wejściowe
	apiParts := strings.Split(apiDetails, ",")
	endpoint := apiParts[0]
	method := apiParts[1]
	errorCodeStr := apiParts[2]
	errorField := apiParts[3]
	
	contextParts := strings.Split(systemContext, ",")
	serviceName := contextParts[0]
	requestID := contextParts[1]
	
	// Przekonwertuj kod błędu na liczbę całkowitą
	errorCode, _ := strconv.Atoi(errorCodeStr)
	
	// TODO: Napisz swój kod poniżej
	// 1. Utwórz strukturę APIError z polami Code, Field i Message
	// 2. Zaimplementuj metodę Error() dla APIError
	// 3. Utwórz instancję APIError na podstawie kodu błędu
	// 4. Utwórz opakowane błędy (na poziomie punktu końcowego i usługi)
	// 5. Użyj errors.As, aby wyodrębnić APIError z łańcucha opakowanych błędów
	// 6. Wyświetl wynik wyodrębnienia i szczegóły błędu
	// 7. Wyświetl łańcuch błędów i końcową analizę
	
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Logika i przepływ sterowania

Poćwicz samodzielnie: Kompilator Go online