Documentation
¶
Overview ¶
Package errorsx provides structured error handling with advanced features for Go applications, including stack traces, error chaining, type classification, and JSON serialization.
This package is designed for production web applications that need:
- Structured error information with unique IDs
- Stack trace capture and management
- Error type classification for different handling strategies
- HTTP status code mapping
- Internationalization support through message data
- Validation error aggregation
- JSON serialization for API responses
Basic Usage:
err := errorsx.New("user.not_found", errorsx.WithType(errorsx.TypeNotFound), errorsx.WithHTTPStatus(404), errorsx.WithMessage(map[string]string{"en": "User not found"}), )
Error Chaining:
err := errorsx.New("database.connection_failed"). WithCause(originalErr). WithCallerStack()
Validation Errors:
verr := errorsx.NewValidationError("validation.failed") verr.AddFieldError("email", "required", "Email is required") verr.AddFieldError("age", "min_value", map[string]int{"min": 18})
Example ¶
Example demonstrates basic error creation and configuration.
err := errorsx.New("user.not_found", errorsx.WithHTTPStatus(404), errorsx.WithMessage("User not found"), ).WithNotFound() fmt.Println("Error ID:", err.ID()) fmt.Println("Error Type:", err.Type()) fmt.Println("Error Message:", err.Error())
Output: Error ID: user.not_found Error Type: errorsx.unknown Error Message: user.not_found
Example (WebAPI) ¶
Example_webAPI demonstrates a complete web API error handling pattern.
// Simulate a web API handler err := handleUserCreation("", "weak") if err != nil { // Handle different error types switch { case errorsx.HasType(err, errorsx.TypeValidation): log.Printf("Validation error: %v", err) // Return HTTP 422 with validation details if verr, ok := err.(*errorsx.ValidationError); ok { jsonData, jsonErr := json.Marshal(verr) if jsonErr != nil { fmt.Printf("JSON marshaling error: %v\n", jsonErr) return } fmt.Printf("HTTP 422 Response: %s\n", jsonData) } case errorsx.HasType(err, errorsx.TypeUnknown): log.Printf("Unknown error: %v", err) // Return HTTP 500 with generic message fmt.Println("HTTP 500 Response: Internal server error") default: log.Printf("Unknown error: %v", err) fmt.Println("HTTP 500 Response: Unknown error") } }
Output: HTTP 422 Response: {"id":"user.validation_failed","type":"errorsx.validation","message_data":"Please fix the validation errors","message":"Please fix the validation errors","field_errors":[{"field":"email","code":"required","message":"Email is required","translated_message":"Email is required"},{"field":"password","code":"weak","message":"Password is too weak","translated_message":"Password is too weak"}]}
Index ¶
- Constants
- func DefaultFieldTranslator(field, code string, message any) string
- func DefaultSummaryTranslator(fieldErrors []FieldError, messageData any) string
- func FullStackTrace(err error) string
- func HTTPStatus(err error) int
- func HasType(err error, typ ErrorType) bool
- func IsNotFound(err error) bool
- func IsRetryable(err error) bool
- func Join(errs ...error) error
- func Message[T any](err error) (T, bool)
- func MessageOr[T any](err error, fallback T) T
- func ReplaceMessage(err error, data any) error
- func RootCause(err error) error
- func RootStackTrace(err error) string
- type Error
- func (e *Error) Error() string
- func (e *Error) HTTPStatus() int
- func (e *Error) ID() string
- func (e *Error) Is(target error) bool
- func (e *Error) IsNotFound() bool
- func (e *Error) IsRetryable() bool
- func (e *Error) MarshalJSON() ([]byte, error)
- func (e *Error) StackFrames() []uintptr
- func (e *Error) Stacks() []StackTrace
- func (e *Error) Type() ErrorType
- func (e *Error) Unwrap() error
- func (e *Error) WithCallerStack() *Error
- func (e *Error) WithCause(cause error) *Error
- func (e *Error) WithHTTPStatus(status int) *Error
- func (e *Error) WithMessage(data any) *Error
- func (e *Error) WithNotFound() *Error
- func (e *Error) WithReason(reason string, params ...any) *Error
- func (e *Error) WithRetryable() *Error
- func (e *Error) WithStack(skip int) *Error
- func (e *Error) WithStackTraceCleaner(cleaner StackTraceCleaner) *Error
- func (e *Error) WithType(typ ErrorType) *Error
- type ErrorType
- type FieldError
- type FieldTranslator
- type Option
- type StackTrace
- type StackTraceCleaner
- type SummaryTranslator
- type ValidationError
- func (v *ValidationError) AddFieldError(field, code string, message any)
- func (v *ValidationError) Error() string
- func (v *ValidationError) HTTPStatus() int
- func (v *ValidationError) MarshalJSON() ([]byte, error)
- func (v *ValidationError) Unwrap() error
- func (v *ValidationError) WithFieldTranslator(t FieldTranslator) *ValidationError
- func (v *ValidationError) WithHTTPStatus(status int) *ValidationError
- func (v *ValidationError) WithMessage(data any) *ValidationError
- func (v *ValidationError) WithSummaryTranslator(t SummaryTranslator) *ValidationError
Examples ¶
Constants ¶
const ( // MaxStackFrames defines the maximum number of stack frames to capture // when creating a stack trace. This prevents excessive memory usage // while still providing sufficient debugging information. MaxStackFrames = 32 )
Variables ¶
This section is empty.
Functions ¶
func DefaultFieldTranslator ¶
DefaultFieldTranslator returns the message as-is if it's a string, otherwise formats it.
func DefaultSummaryTranslator ¶
func DefaultSummaryTranslator(fieldErrors []FieldError, messageData any) string
DefaultSummaryTranslator returns a simple summary message.
func FullStackTrace ¶
FullStackTrace returns the full stack trace chain for the error.
func HTTPStatus ¶
HTTPStatus extracts the HTTP status code from any error. If the error is an errorsx.Error with a status code, returns that code. Otherwise returns 0.
This function enables HTTP status code extraction from any error in an error chain, making it useful for middleware and error handlers.
Example:
status := errorsx.HTTPStatus(err) if status != 0 { w.WriteHeader(status) } else { w.WriteHeader(500) // Default to internal server error }
Returns 0 if no HTTP status is found or if err is nil.
func HasType ¶
HasType checks if an error chain contains any errors of the specified ErrorType. This is a convenience function that returns true if FilterByType would return a non-empty slice.
Example:
if errorsx.HasType(err, errorsx.TypeValidation) { // Handle validation errors return handleValidationError(err) }
This function is more efficient than FilterByType when you only need to check for the presence of a specific error type without accessing the errors themselves.
func IsNotFound ¶
IsNotFound checks if any error in the error chain represents a "not found" condition. This function works with any error type and traverses the error chain to find errorsx.Error instances marked as "not found".
Example:
if errorsx.IsNotFound(err) { // Handle not found case - typically return 404 return handleNotFound() }
Returns false if err is nil or no "not found" errors are found in the chain.
func IsRetryable ¶ added in v0.1.2
IsRetryable checks if any error in the error chain represents a retryable condition. This function works with any error type and traverses the error chain to find errorsx.Error instances marked as retryable.
Example:
if errorsx.IsRetryable(err) { // Retry the operation return retryOperation() }
Returns false if err is nil or no retryable errors are found in the chain.
func Join ¶
Join returns an error that wraps the given errors. Any nil error values are discarded. Returns nil if all errors are nil. The error formats as the concatenation of the strings obtained by calling the Error method of each element with a separating "; ".
This function is compatible with Go's standard errors.Join behavior and supports both errors.Is and errors.As for unwrapping.
Example:
err1 := errorsx.New("validation.email") err2 := errorsx.New("validation.password") combined := errorsx.Join(err1, err2) // combined.Error() returns "validation.email; validation.password"
Example ¶
ExampleJoin demonstrates joining multiple errors together.
err1 := errorsx.New("validation.email", errorsx.WithType(errorsx.TypeValidation)) err2 := errorsx.New("validation.password", errorsx.WithType(errorsx.TypeValidation)) err3 := errors.New("database connection failed") // Join multiple errors combined := errorsx.Join(err1, err2, err3) fmt.Println("Combined error:", combined.Error()) // Check for specific errors if errors.Is(combined, err1) { fmt.Println("Email validation error found") } // Filter by type validationErrors := errorsx.FilterByType(combined, errorsx.TypeValidation) fmt.Printf("Found %d validation errors\n", len(validationErrors))
Output: Combined error: validation.email; validation.password; database connection failed Email validation error found Found 2 validation errors
func Message ¶
Message extracts typed message data from an error. It performs type assertion to convert the message data to the specified type T. Returns the message data and true if successful, or zero value and false if the error is not an errorsx.Error or the type assertion fails.
Example:
err := errorsx.New("user.not_found").WithMessage(map[string]string{ "en": "User not found", }) if msg, ok := errorsx.Message[map[string]string](err); ok { fmt.Println(msg["en"]) // "User not found" }
This function is particularly useful for extracting structured message data such as translation maps or validation error details.
func MessageOr ¶
MessageOr extracts typed message data from an error with a fallback value. If the error is not an errorsx.Error or the type assertion fails, it returns the provided fallback value instead of a zero value.
Example:
msg := errorsx.MessageOr(err, "Unknown error") // msg will be the extracted message or "Unknown error" if extraction fails
This function provides a convenient way to safely extract message data without needing to check the boolean return value.
func ReplaceMessage ¶
ReplaceMessage replaces the message data of any error. If the error is an errorsx.Error, it returns a copy with the new message data. If the error is a standard Go error, it wraps it in a new errorsx.Error with the provided message data.
This function is useful for adding user-friendly messages to errors that may come from external libraries or system calls.
Example:
err := os.Open("nonexistent.txt") // returns *os.PathError userErr := errorsx.ReplaceMessage(err, "File not found") // userErr is now an errorsx.Error with the original error as cause
Example ¶
ExampleReplaceMessage demonstrates adding user-friendly messages to any error.
// Start with a standard Go error originalErr := errors.New("sql: no rows in result set") // Add user-friendly message userErr := errorsx.ReplaceMessage(originalErr, "User not found") fmt.Println("Original error:", originalErr.Error()) fmt.Println("User-friendly error:", userErr.Error()) // The original error is still accessible if errors.Is(userErr, originalErr) { fmt.Println("Original error is still in the chain") }
Output: Original error: sql: no rows in result set User-friendly error: unknown.error Original error is still in the chain
func RootCause ¶
RootCause returns the deepest error in the error chain. If an *Error with a cause is found, it follows the cause; otherwise, it unwraps. Returns the last error in the chain (the root cause).
func RootStackTrace ¶
RootStackTrace returns the stack trace of the root cause error, if available.
Types ¶
type Error ¶
type Error struct {
// contains filtered or unexported fields
}
Error represents a structured, chainable error with stack trace and attributes. It provides enhanced error handling capabilities beyond Go's standard error interface, including unique identification, type classification, HTTP status mapping, and structured message data for internationalization.
Error implements the standard error interface and supports error unwrapping through the Unwrap() method, making it compatible with Go's error handling patterns including errors.Is() and errors.As().
func FilterByType ¶
FilterByType recursively searches an error chain and returns all errorsx.Error instances that match the specified ErrorType. This function traverses both simple error chains (via Unwrap()) and joined errors (multiple errors).
The function prevents duplicate results by tracking already-seen errors.
Example:
err1 := errorsx.New("validation.required", errorsx.WithType(errorsx.TypeValidation)) err2 := errorsx.New("validation.format", errorsx.WithType(errorsx.TypeValidation)) combined := errorsx.Join(err1, err2) validationErrors := errorsx.FilterByType(combined, errorsx.TypeValidation) // Returns []*Error containing both validation errors
Returns an empty slice if no errors of the specified type are found.
Example ¶
ExampleFilterByType demonstrates filtering errors by type.
// Define custom error type const TypeAuthentication errorsx.ErrorType = "myapp.authentication" // Create multiple errors of different types validationErr := errorsx.New("email.invalid", errorsx.WithType(errorsx.TypeValidation)) authErr := errorsx.New("token.expired", errorsx.WithType(TypeAuthentication)) // Join errors together combined := errorsx.Join(validationErr, authErr) // Filter by validation type validationErrors := errorsx.FilterByType(combined, errorsx.TypeValidation) fmt.Printf("Found %d validation errors\n", len(validationErrors)) // Check if authentication errors exist hasAuth := errorsx.HasType(combined, TypeAuthentication) fmt.Printf("Has authentication errors: %v\n", hasAuth)
Output: Found 1 validation errors Has authentication errors: true
func New ¶
New creates a new Error with the given id and options. The id serves as a unique identifier for the error type and is used for error comparison with errors.Is().
Example:
err := errorsx.New("user.not_found", errorsx.WithType(errorsx.TypeNotFound), errorsx.WithHTTPStatus(404), errorsx.WithMessage("User not found"), )
The id should follow a hierarchical naming convention (e.g., "domain.operation.reason") to facilitate error categorization and handling.
func NewNotFound ¶
NewNotFound creates a new "not found" error with the given ID. This is a convenience constructor for the common pattern of creating errors that represent missing resources.
Example:
err := errorsx.NewNotFound("user.not_found") // Equivalent to: errorsx.New("user.not_found").WithNotFound()
func NewRetryable ¶ added in v0.1.2
NewRetryable creates a new retryable error with the given ID. This is a convenience constructor for creating errors that indicate the operation can be safely retried.
Example:
err := errorsx.NewRetryable("connection.timeout") // Equivalent to: errorsx.New("connection.timeout").WithRetryable()
func (*Error) Error ¶
Error implements the standard Go error interface. It returns the technical message set by WithReason(), or the error ID if no specific message was provided.
func (*Error) HTTPStatus ¶
HTTPStatus returns the HTTP status code associated with this error. Returns 0 if no HTTP status code was set.
This method is typically used by web frameworks or middleware to determine the appropriate HTTP response code for an error.
func (*Error) ID ¶
ID returns the unique identifier of the error. This ID is used for error comparison and categorization.
func (*Error) Is ¶
Is implements custom error comparison for errors.Is(). Two errorsx.Error instances are considered equal if they have the same ID. For non-errorsx errors, it delegates to the underlying error's Is method or compares the cause error.
This enables error identification based on semantic meaning rather than instance equality, supporting error handling patterns like:
if errors.Is(err, errorsx.New("user.not_found")) { // Handle user not found error }
func (*Error) IsNotFound ¶
IsNotFound returns true if this error represents a "not found" condition. This provides a semantic way to check for missing resources or entities.
func (*Error) IsRetryable ¶ added in v0.1.2
IsRetryable returns true if this error represents a retryable condition. This provides a semantic way to check if an operation can be safely retried.
func (*Error) MarshalJSON ¶
MarshalJSON implements the json.Marshaler interface for Error, providing structured output for logging and APIs.
func (*Error) StackFrames ¶ added in v0.1.1
StackFrames returns the stack frames for sentry-go compatibility. This method is compatible with go-errors/errors and other libraries that expect a StackFrames() []uintptr method for extracting stack traces.
If multiple stack traces are available, it returns the most recent one (the first in the slice) as this represents the most direct error location. Returns an empty slice if no stack traces are available.
func (*Error) Stacks ¶
func (e *Error) Stacks() []StackTrace
Stacks returns the stack traces associated with the error.
func (*Error) Type ¶
Type returns the ErrorType of the error. Returns TypeUnknown if no specific type was set.
func (*Error) Unwrap ¶
Unwrap returns the underlying cause error, enabling Go's error unwrapping functionality. This allows errors.Is() and errors.As() to traverse the error chain to find specific error types or values.
Returns nil if no underlying cause was set.
func (*Error) WithCallerStack ¶
WithCallerStack returns a copy of the error with a stack trace captured from the caller's location. This is a convenience method equivalent to WithStack(1), which excludes the WithCallerStack call itself from the stack trace.
This is the most commonly used method for adding stack traces, as it captures the location where the error was created or wrapped, not the location of the WithCallerStack call.
Example:
func processUser(id string) error { if user := findUser(id); user == nil { return errorsx.New("user.not_found").WithCallerStack() // Stack trace will point to this line, not inside WithCallerStack } return nil }
Example ¶
ExampleError_WithCallerStack demonstrates stack trace capture.
err := createUserError() // Check if error has stack trace if xerr, ok := err.(*errorsx.Error); ok { stacks := xerr.Stacks() if len(stacks) > 0 { fmt.Printf("Stack trace captured with %d frames\n", len(stacks[0].Frames)) fmt.Printf("Stack message: %s\n", stacks[0].Msg) } }
Output: Stack trace captured with 8 frames Stack message: user.creation_failed
func (*Error) WithCause ¶
WithCause returns a copy of the error with the specified underlying cause. If the error doesn't already have a stack trace, this method automatically captures one to preserve the error's origin point.
This method is essential for error chaining, allowing you to wrap lower-level errors with higher-level context while maintaining the full error chain.
Parameters:
- cause: The underlying error that caused this error
Example:
// Wrap a database error with business logic context dbErr := db.Query("SELECT ...") if dbErr != nil { return errorsx.New("user.fetch_failed"). WithCause(dbErr). WithMessage("Failed to fetch user data") }
The resulting error chain allows for:
- errors.Is(err, dbErr) // true
- errors.Unwrap(err) // returns dbErr
- Stack trace pointing to the WithCause call location
Example ¶
ExampleError_WithCause demonstrates error chaining and stack traces.
// Simulate a low-level error dbErr := errors.New("connection timeout") // Wrap with business logic error err := errorsx.New("user.fetch_failed"). WithCause(dbErr). WithMessage("Failed to fetch user data") // Check if the original error is in the chain if errors.Is(err, dbErr) { fmt.Println("Original database error found in chain") } // Unwrap to get the original error originalErr := errors.Unwrap(err) fmt.Println("Original error:", originalErr.Error())
Output: Original database error found in chain Original error: connection timeout
func (*Error) WithHTTPStatus ¶
WithHTTPStatus returns a copy of the error with the specified HTTP status code. This is useful for web applications that need to map errors to appropriate HTTP response codes.
Example:
err := errorsx.New("user.not_found"). WithHTTPStatus(404). WithMessage("User not found")
Common HTTP status codes for errors:
- 400 Bad Request: Client errors, validation failures
- 401 Unauthorized: Authentication required
- 403 Forbidden: Access denied
- 404 Not Found: Resource not found
- 409 Conflict: Resource conflicts
- 422 Unprocessable Entity: Semantic validation errors
- 500 Internal Server Error: Server-side errors
func (*Error) WithMessage ¶
WithMessage returns a copy of the error with the given message data. This data is typically used for user-facing messages and can be any type, often a string or a map for internationalization.
Example with string message:
err := errorsx.New("user.not_found").WithMessage("User not found")
Example with i18n data:
err := errorsx.New("user.not_found").WithMessage(map[string]string{ "en": "User not found", "ja": "ユーザーが見つかりません", })
The message data can be extracted using the Message() or MessageOr() functions.
Example ¶
ExampleError_WithMessage demonstrates setting user-facing message data.
// Simple string message err1 := errorsx.New("user.not_found"). WithMessage("User not found") // Internationalization data err2 := errorsx.New("user.not_found"). WithMessage(map[string]string{ "en": "User not found", "ja": "ユーザーが見つかりません", }) // Extract English message if msg, ok := errorsx.Message[map[string]string](err2); ok { fmt.Println("English:", msg["en"]) fmt.Println("Japanese:", msg["ja"]) } // Using MessageOr for fallback simpleMsg := errorsx.MessageOr[string](err1, "Unknown error") fmt.Println("Simple message:", simpleMsg)
Output: English: User not found Japanese: ユーザーが見つかりません Simple message: User not found
func (*Error) WithNotFound ¶
WithNotFound returns a copy of the error marked as a "not found" error. This is a convenience method for common "not found" scenarios.
Example:
err := errorsx.New("user.not_found"). WithNotFound(). WithHTTPStatus(404)
func (*Error) WithReason ¶
WithReason returns a copy of the error with the given technical message. This message is intended for logging and debugging purposes and supports format string parameters similar to fmt.Sprintf.
Example:
err := errorsx.New("database.query_failed"). WithReason("Failed to execute query: %s", query)
Note: This creates a shallow copy of the error, preserving the original error's stack traces and other attributes.
Example ¶
ExampleError_WithReason demonstrates setting technical error messages.
err := errorsx.New("database.query_failed"). WithReason("Failed to execute query: %s", "SELECT * FROM users") fmt.Println(err.Error())
Output: Failed to execute query: SELECT * FROM users
func (*Error) WithRetryable ¶ added in v0.1.2
WithRetryable returns a copy of the error marked as retryable. This indicates that the operation that caused the error can be safely retried.
Example:
err := errorsx.New("network.timeout"). WithRetryable(). WithHTTPStatus(503)
Example ¶
ExampleError_WithRetryable demonstrates retryable error handling.
// Create a retryable error for temporary failures err := errorsx.New("service.temporarily_unavailable"). WithRetryable(). WithHTTPStatus(503). WithMessage("Service temporarily unavailable. Please try again.") // Check if error is retryable if errorsx.IsRetryable(err) { fmt.Println("Error is retryable") fmt.Printf("HTTP Status: %d\n", err.HTTPStatus()) } // Using the convenience constructor timeoutErr := errorsx.NewRetryable("connection.timeout"). WithReason("Connection timed out after 30 seconds") fmt.Printf("Timeout error is retryable: %v\n", errorsx.IsRetryable(timeoutErr))
Output: Error is retryable HTTP Status: 503 Timeout error is retryable: true
func (*Error) WithStack ¶
WithStack returns a copy of the error with a stack trace captured at the specified skip level. The skip parameter determines how many stack frames to skip when capturing the trace, allowing you to exclude wrapper functions from the stack trace.
If the error already has a stack trace (isStacked is true), it returns the error unchanged to prevent duplicate stack traces in the same error chain.
Parameters:
- skip: Number of stack frames to skip (0 = include WithStack call, 1 = exclude it)
Example:
// Capture stack trace including this function call err := errorsx.New("something.failed").WithStack(0) // Capture stack trace excluding this function call err := errorsx.New("something.failed").WithStack(1)
func (*Error) WithStackTraceCleaner ¶
func (e *Error) WithStackTraceCleaner(cleaner StackTraceCleaner) *Error
WithStackTraceCleaner returns a copy of the error with a custom stack trace cleaner function. The cleaner function will be applied when the stack trace is formatted for display, allowing for customization of the stack trace output.
Example:
cleaner := func(frames []string) []string { // Filter out Go runtime frames var filtered []string for _, frame := range frames { if !strings.Contains(frame, "runtime.") { filtered = append(filtered, frame) } } return filtered } err := errorsx.New("db.connection_failed"). WithCallerStack(). WithStackTraceCleaner(cleaner)
type ErrorType ¶
type ErrorType string
ErrorType represents a string-based error category for classification and filtering. Error types enable systematic error handling by allowing code to identify and respond to different categories of errors consistently.
Example usage:
// Define custom error types const TypeAuthentication ErrorType = \"myapp.authentication\" err := errorsx.New("auth.failed", errorsx.WithType(TypeAuthentication)) if errorsx.HasType(err, TypeAuthentication) { // Handle authentication errors }
const ( // TypeInitialization represents errors that occur during system or component initialization. TypeInitialization ErrorType = "errorsx.initialization" // TypeUnknown is the default error type when no specific type is assigned. TypeUnknown ErrorType = "errorsx.unknown" // TypeValidation represents errors related to input validation and data constraints. TypeValidation ErrorType = "errorsx.validation" )
Predefined error types for common error categories. Applications can define additional custom types as needed.
type FieldError ¶
type FieldError struct { Field string `json:"field"` // Form field name Code string `json:"code"` // Error code (e.g., "required", "invalid_format") Message any `json:"message"` // Message data (can be string, object, or any type) }
FieldError represents individual error information that occurred for a specific field.
type FieldTranslator ¶
FieldTranslator is a function type that translates individual field error messages. It receives field name, error code, and message data to generate a localized message.
type Option ¶
type Option func(*Error)
Option represents a function that configures an Error during creation. Options follow the functional options pattern, allowing flexible and extensible error configuration.
func WithHTTPStatus ¶
WithHTTPStatus sets the HTTP status code for web API responses. This allows automatic HTTP status code mapping in web handlers.
Example:
err := errorsx.New("user.not_found", errorsx.WithHTTPStatus(404), )
func WithMessage ¶
WithMessage sets the message data for user-facing display. The data can be any type - string for simple messages, or structured data (maps, structs) for internationalization.
Example with simple message:
err := errorsx.New("user.not_found", errorsx.WithMessage("User not found"), )
Example with i18n data:
err := errorsx.New("user.not_found", errorsx.WithMessage(map[string]string{ "en": "User not found", "ja": "ユーザーが見つかりません", }), )
func WithNotFound ¶
func WithNotFound() Option
WithNotFound marks the error as a "not found" error. This is a convenience method that's equivalent to WithType(TypeNotFound) but can be used in combination with other types for more specific classification.
Example:
err := errorsx.New("user.not_found", errorsx.WithNotFound(), errorsx.WithHTTPStatus(404), )
func WithRetryable ¶ added in v0.1.2
func WithRetryable() Option
WithRetryable marks the error as retryable. This indicates that the operation that caused the error can be safely retried, such as temporary network failures or transient service unavailability.
Example:
err := errorsx.New("service.unavailable", errorsx.WithRetryable(), errorsx.WithHTTPStatus(503), )
type StackTrace ¶
type StackTrace struct { // Frames contains the raw program counter values for each stack frame. Frames []uintptr // Msg is a descriptive message about when this stack trace was captured. Msg string }
StackTrace represents a captured call stack with an associated message. It stores the raw program counter values and a descriptive message about when/why the stack trace was captured.
The stack trace can be formatted and displayed using various methods, and can be customized with StackTraceCleaner functions.
type StackTraceCleaner ¶
StackTraceCleaner is a function type for customizing stack trace output. It receives a slice of formatted stack frame strings and returns a modified slice, allowing for filtering, formatting, or annotating stack traces.
Example use cases:
- Filtering out internal framework code
- Highlighting application-specific code
- Adding source code context
- Anonymizing sensitive paths
Example implementation:
cleaner := func(frames []string) []string { var cleaned []string for _, frame := range frames { if !strings.Contains(frame, "internal/") { cleaned = append(cleaned, frame) } } return cleaned }
type SummaryTranslator ¶
type SummaryTranslator func(fieldErrors []FieldError, messageData any) string
SummaryTranslator is a function type that translates a summary message. It receives field errors and base message data to generate a localized summary.
type ValidationError ¶
type ValidationError struct { BaseError *Error `json:"-"` // Existing errorsx.Error (ID, Type, HTTPStatus, etc.) FieldErrors []FieldError `json:"field_errors"` // Error list for each field name // contains filtered or unexported fields }
ValidationError is an error type that holds multiple field errors together. By having an existing *Error internally, it can be easily combined with business layer errors. Implements Error() to satisfy the error interface, and additionally implements MarshalJSON() to return field errors for JSON output.
func NewValidationError ¶
func NewValidationError(id string) *ValidationError
NewValidationError creates a new instance as a form input validation error.
id: ID that uniquely identifies the validation error (e.g., "validation.failed")
Example ¶
ExampleNewValidationError demonstrates validation error handling.
verr := errorsx.NewValidationError("user.validation_failed") verr.WithHTTPStatus(422) verr.WithMessage("Please fix the following errors") // Add individual field errors verr.AddFieldError("email", errorCodeRequired, "Email is required") verr.AddFieldError("age", "min_value", map[string]int{ "min": 18, "current": 16, }) verr.AddFieldError("username", "taken", "Username is already taken") // Demonstrate error message fmt.Println("Error message:", verr.Error()) // Demonstrate JSON serialization jsonData, err := json.MarshalIndent(verr, "", " ") if err != nil { fmt.Printf("JSON marshaling error: %v\n", err) return } fmt.Println("JSON representation:") fmt.Println(string(jsonData))
Output: Error message: user.validation_failed: email: Email is required; age: map[current:16 min:18]; username: Username is already taken JSON representation: { "id": "user.validation_failed", "type": "errorsx.validation", "message_data": "Please fix the following errors", "message": "Please fix the following errors", "field_errors": [ { "field": "email", "code": "required", "message": "Email is required", "translated_message": "Email is required" }, { "field": "age", "code": "min_value", "message": { "current": 16, "min": 18 }, "translated_message": "map[current:16 min:18]" }, { "field": "username", "code": "taken", "message": "Username is already taken", "translated_message": "Username is already taken" } ] }
func (*ValidationError) AddFieldError ¶
func (v *ValidationError) AddFieldError(field, code string, message any)
AddFieldError adds validation error information for a specific field. This method accumulates field errors that will be included in the final validation error response.
Parameters:
- field: The name of the form field (e.g., "email", "password")
- code: Machine-readable error code (e.g., "required", "min_length", "invalid_format")
- message: Human-readable message or structured data for the error
Examples:
// Simple string message verr.AddFieldError("email", "required", "Email address is required") // Structured message data for complex validation rules verr.AddFieldError("password", "min_length", map[string]int{ "min": 8, "current": 3, }) // Internationalization data verr.AddFieldError("username", "taken", map[string]string{ "en": "Username is already taken", "ja": "ユーザー名は既に使用されています", })
func (*ValidationError) Error ¶
func (v *ValidationError) Error() string
Error implements the standard error interface. It returns a human-readable string that includes the base error message and details about each field error. The format is suitable for logging and debugging purposes.
Example output: "validation failed: email: required; password: too short".
func (*ValidationError) HTTPStatus ¶
func (v *ValidationError) HTTPStatus() int
HTTPStatus returns the HTTP status code associated with this validation error. This is typically used by web frameworks to set appropriate HTTP response codes. Defaults to 0 if no status was explicitly set.
Common validation error status codes:
- 400 Bad Request: General validation failures
- 422 Unprocessable Entity: Semantic validation errors
func (*ValidationError) MarshalJSON ¶
func (v *ValidationError) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler to provide custom JSON serialization. This method creates a structured JSON representation suitable for API responses, including both the raw message data and translated messages for each field error.
The JSON structure includes:
- id: The unique error identifier
- type: The error type (typically "validation")
- message_data: The raw message data from WithMessage()
- message: The translated summary message
- field_errors: Array of field-specific errors with translations
Example JSON output:
{ "id": "user.validation_failed", "type": "validation", "message_data": "Please fix the following errors", "message": "Validation failed with 2 error(s)", "field_errors": [ { "field": "email", "code": "required", "message": "Email is required", "translated_message": "Email is required" }, { "field": "password", "code": "min_length", "message": {"min": 8, "current": 3}, "translated_message": "Password must be at least 8 characters" } ] }
This format enables both programmatic error handling (using codes and structured data) and user-friendly error display (using translated messages).
func (*ValidationError) Unwrap ¶
func (v *ValidationError) Unwrap() error
Unwrap returns the underlying base error, enabling Go's error unwrapping functionality. This allows ValidationError to participate in error chains and be compatible with errors.Is() and errors.As().
Example:
if errors.Is(validationErr, someSpecificError) { // Handle specific error type }
func (*ValidationError) WithFieldTranslator ¶
func (v *ValidationError) WithFieldTranslator(t FieldTranslator) *ValidationError
WithFieldTranslator sets a custom translator for individual field error messages. This enables localization and custom formatting of field-specific error messages.
Example:
customFieldTranslator := func(field, code string, message any) string { switch code { case "required": return fmt.Sprintf("The %s field is required", field) default: return fmt.Sprintf("%v", message) } } verr.WithFieldTranslator(customFieldTranslator)
Example ¶
ExampleValidationError_WithFieldTranslator demonstrates custom field error formatting.
// Custom field translator for better error messages fieldTranslator := func(field, code string, message any) string { switch code { case errorCodeRequired: return fmt.Sprintf("The %s field is required", field) case "min_value": if data, ok := message.(map[string]int); ok { return fmt.Sprintf("The %s must be at least %d (current: %d)", field, data["min"], data["current"]) } case "taken": return fmt.Sprintf("The %s '%v' is already taken", field, message) } return fmt.Sprintf("%v", message) } verr := errorsx.NewValidationError("user.validation_failed"). WithFieldTranslator(fieldTranslator) verr.AddFieldError("email", errorCodeRequired, nil) verr.AddFieldError("age", "min_value", map[string]int{"min": 18, "current": 16}) verr.AddFieldError("username", "taken", "john_doe") fmt.Println(verr.Error())
Output: user.validation_failed: email: The email field is required; age: The age must be at least 18 (current: 16); username: The username 'john_doe' is already taken
func (*ValidationError) WithHTTPStatus ¶
func (v *ValidationError) WithHTTPStatus(status int) *ValidationError
WithHTTPStatus sets the HTTP status code for the validation error.
func (*ValidationError) WithMessage ¶
func (v *ValidationError) WithMessage(data any) *ValidationError
WithMessage sets the message data for the base error.
func (*ValidationError) WithSummaryTranslator ¶
func (v *ValidationError) WithSummaryTranslator(t SummaryTranslator) *ValidationError
WithSummaryTranslator sets a custom translator for generating the overall validation error summary message. This is useful for internationalization or custom error message formatting.
Example:
customSummary := func(fieldErrors []FieldError, messageData any) string { return fmt.Sprintf("Validation failed for %d fields", len(fieldErrors)) } verr.WithSummaryTranslator(customSummary)