Integration, Migration & FAQ

August 29, 2025 · View on GitHub

Interfaces

go-errors provides interfaces for advanced error handling:

  • ErrorCoder: Extracts the error code
  • Retryable: Indicates if an error is retryable
  • UserMessager: Extracts a user-friendly message

Example

var coder errors.ErrorCoder = err
code := coder.ErrorCode()

var retry errors.Retryable = err
if retry.IsRetryable() { /* ... */ }

var um errors.UserMessager = err
msg := um.UserMessage()

Testing & Coverage

Run all tests:

go test -v ./...

Check coverage:

go test -cover ./...
  • Write tests for all custom error codes and logic in your application.
  • Use table-driven tests for error scenarios.
  • Aim for high coverage to ensure reliability.

Integration in Real Projects

  • Use go-errors for all error creation and propagation in your services.
  • Wrap errors at API/service boundaries to add context and user messages.
  • Serialize errors to JSON for API responses.
  • Use error codes for programmatic error handling in clients.

Example: REST API Handler

func handler(w http.ResponseWriter, r *http.Request) {
    err := doSomething()
    if err != nil {
        apiErr, _ := err.(*errors.Error)
        http.Error(w, apiErr.UserMessage(), 400)
        // Optionally log apiErr.Stack.String() for debugging
    }
}

Migration Guide: From Standard Errors to go-errors

This guide helps you migrate your Go project from standard error handling to go-errors, step by step.

1. Install go-errors

go get github.com/agilira/go-errors

2. Update Imports

Replace:

import "errors"

with:

import "github.com/agilira/go-errors"

3. Define Error Codes

Instead of using only error messages, define string constants for error codes:

const ErrCodeValidation = "VALIDATION_ERROR"

4. Replace errors.New and fmt.Errorf

Before:

return errors.New("validation failed")

After:

return errors.New(ErrCodeValidation, "Validation failed")

5. Wrapping Errors

Before:

return fmt.Errorf("db error: %w", err)

After:

return errors.Wrap(err, "DB_ERROR", "db error")

6. Add User Messages and Context

err := errors.New(ErrCodeValidation, "Validation failed").
    WithUserMessage("Please check your input").
    WithContext("field", "email").
    WithSeverity("warning")

7. Use Helpers for Inspection

Replace manual error checks with helpers:

if errors.HasCode(err, ErrCodeValidation) { /* ... */ }
root := errors.RootCause(err)

8. Update API/Handler Logic

Return user-friendly messages in APIs:

apiErr, _ := err.(*errors.Error)
http.Error(w, apiErr.UserMessage(), 400)

9. Testing

Update your tests to check error codes and user messages, not just error strings.

Example: Before and After

Before:

if err != nil {
    if errors.Is(err, sql.ErrNoRows) {
        return errors.New("not found")
    }
    return fmt.Errorf("db error: %w", err)
}

After:

if err != nil {
    if errors.Is(err, sql.ErrNoRows) {
        return errors.New("NOT_FOUND", "not found").WithUserMessage("Resource not found")
    }
    return errors.Wrap(err, "DB_ERROR", "db error")
}

Tips

  • Migrate incrementally: start from leaf packages and move up.
  • Use go-errors everywhere for consistency.
  • Use error codes for programmatic handling, user messages for UI/API.

FAQ

Q: Can I define my own error codes? A: Yes, define them as string constants in your application.

Q: Is go-errors compatible with the standard errors package? A: Yes, it supports errors.Is, errors.As, and errors.Unwrap.

Q: How do I attach extra context to an error? A: Use the WithContext method.

Q: How do I return user-friendly messages in APIs? A: Use WithUserMessage and UserMessage().

Q: Is stacktrace capture expensive? A: No, it is lightweight and only captured when wrapping errors.


go-errors • an AGILira library