Menu
Coddy logo textTech

Unwrapping with `errors.As`

Part of the Logic & Flow section of Coddy's GO journey — lesson 41 of 68.

While errors.Is helps you identify specific error values in a chain, sometimes you need to access the actual fields and data of a custom error type. The errors.As function provides this capability by finding the first error in a chain that matches a specific type and extracting it for inspection.

The errors.As function takes two parameters: the error to examine and a pointer to a variable of the target error type. If it finds a matching error type in the chain, it sets your variable to that error and returns true:

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

This is particularly powerful when working with custom error types that contain additional context. Unlike errors.Is which only checks for equality, errors.As extracts the actual error instance, allowing you to access its fields and methods. This makes error handling more sophisticated and informative in complex applications.

quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

challenge icon

Challenge

Easy

Build an API error handling system that uses errors.As to extract and examine custom error types from wrapped error chains. This challenge demonstrates how to use errors.As to access the fields and data of specific custom error types, even when they've been wrapped with additional context.

You will receive two inputs:

  • A string containing API request details in the format "endpoint,method,error_code,error_field" (e.g., "/users,POST,400,email")
  • A string containing system context in the format "service_name,request_id" (e.g., "UserAPI,req_12345")

Your task is to:

  1. Create a custom error type called APIError struct with three fields:
    • Code (int) - the HTTP status code
    • Field (string) - the field that caused the error
    • Message (string) - a description of the error
  2. Implement the Error() string method for APIError that returns: "API error [code]: [message] (field: [field])"
  3. Parse the first input by splitting on commas to get endpoint, method, error code, and error field
  4. Parse the second input by splitting on commas to get service name and request ID
  5. Convert the error code string to an integer
  6. Create an APIError instance based on the error code:
    • If code is 400: message "invalid request data"
    • If code is 401: message "authentication required"
    • If code is 404: message "resource not found"
    • If code is 500: message "internal server error"
    • For any other code: message "unknown error"
  7. Create an endpoint-level wrapped error using fmt.Errorf with %w: "[method] [endpoint] failed: %w"
  8. Create a service-level wrapped error: "[service_name] request [request_id] failed: %w"
  9. Use errors.As to extract the APIError from the wrapped error chain and display the extraction result:
    • If extraction succeeds: "API error extracted successfully"
    • If extraction fails: "Failed to extract API error"
  10. If the extraction succeeded, display the extracted error details:
    • "Extracted Error Details:"
    • "Code: [code]"
    • "Field: [field]"
    • "Message: [message]"
    • "Full error: [full_error_message_from_Error_method]"
  11. Display the complete error chain:
    • "Error Chain:"
    • "Original: [original_api_error_message]"
    • "Endpoint level: [endpoint_level_error_message]"
    • "Service level: [service_level_error_message]"
  12. Display a final analysis:
    • "Error Analysis:"
    • "Service: [service_name]"
    • "Request ID: [request_id]"
    • "Endpoint: [method] [endpoint]"
    • "HTTP Status: [code]"
    • "Problem Field: [field]"
    • "Error Category: [error_category]" where error_category is "Client Error" for codes 400-499, "Server Error" for codes 500-599, or "Unknown" for other codes

Use the strings package to split the input strings on commas, the strconv package to convert the error code string to an integer, the errors package for errors.As, and the fmt package for error wrapping. This challenge demonstrates how errors.As allows you to access the specific fields and methods of custom error types within wrapped error chains, enabling sophisticated error handling and analysis.

Cheat sheet

The errors.As function extracts specific error types from error chains, allowing access to custom error fields and methods.

errors.As takes two parameters: the error to examine and a pointer to a variable of the target error type:

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

Unlike errors.Is which only checks for equality, errors.As extracts the actual error instance, enabling access to its fields and methods for more sophisticated error handling.

Try it yourself

package main

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

func main() {
	// Read input
	var apiDetails string
	var systemContext string
	fmt.Scanln(&apiDetails)
	fmt.Scanln(&systemContext)
	
	// Parse inputs
	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]
	
	// Convert error code to integer
	errorCode, _ := strconv.Atoi(errorCodeStr)
	
	// TODO: Write your code below
	// 1. Create APIError struct with Code, Field, Message fields
	// 2. Implement Error() method for APIError
	// 3. Create APIError instance based on error code
	// 4. Create wrapped errors (endpoint-level and service-level)
	// 5. Use errors.As to extract APIError from wrapped error chain
	// 6. Display extraction result and error details
	// 7. Display error chain and final analysis
	
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Logic & Flow