errors
Errors Package
The errors package provides a centralized error handling library for Go applications. It standardizes error codes, messages, and HTTP status codes across services, making error management consistent and efficient.
Features
Standardized Error Codes: Uses a consistent error code format (
xyyzzz) across services.Service Prefixes: Allows setting a service-specific prefix for error codes.
Domain Errors: Provides a
DomainErrorinterface for custom errors.Base Error Embedding: Encourages embedding
BaseErrorfor consistency.Utilities: Includes helper functions for wrapping, unwrapping, and extracting errors.
Category Validation: Validates that error codes align with predefined categories.
Installation
go get github.com/kittipat1413/go-common/framework/errorsDocumentation
For detailed API documentation, examples, and usage patterns, visit the Go Package Documentation.
Getting Started
Setting the Service Prefix
Before using the error handling library, set the service-specific prefix. This helps in identifying which service an error originated from.
Defining Custom Errors
Define custom errors by embedding *errors.BaseError in your error type. This ensures that custom errors conform to the DomainError interface and can be properly handled by the error utilities.
Simplify Error Constructors
To avoid handling errors every time you create a custom error, you can design your constructors to handle any internal errors themselves. This way, your error creation functions can have a simpler signature, returning only the custom error. You can handle internal errors by:
Panicking
If
errors.NewBaseErrorreturns anerror, it likely indicates a misconfiguration or coding error (e.g., invalid error code). In such cases, it's acceptable to panic during development to catch the issue early.Returning an Error Interface ✅
If you want the option to handle the error in the calling function, you can modify your constructor to return an
errorinterface. This allows proper handling ofErrBaseErrorCreationFailed, which is returned when NewBaseError fails due to invalid error codes or categories.Using
init()to Initialize Predefined ErrorsYou can simplify handling predefined errors by initializing them at the package level. This approach removes the need to handle errors every time you use these predefined errors. If
NewBaseErrorfails during initialization (e.g., due to a misconfiguration),log.Fatalwill immediately halt the program and output the error. This way, issues are caught early at startup rather than during runtime.After defining these errors, you can use them directly in your code by referencing
myerrors.ErrBadRequestormyerrors.ErrNotFound. Since they are pre-initialized at the package level, they are always available without needing additional error handling for creation.
Why Wrap BaseError in a Custom Type?
BaseError in a Custom Type?In Go, it’s common to wrap a base error type inside a more specific domain error type (like UserNotFoundError). Here’s why this approach is beneficial:
Stronger Type Assertions
When handling errors, using a custom error type allows for better type checking with
errors.As().
Better Encapsulation of Business Logic
A custom error type keeps domain logic inside the error itself, making it easier to manage.
Improves Readability & Maintains Domain Clarity
Without a Custom Error Type:
With a Custom Error Type:
Using the Error Handling Utilities
Adding Context with a Prefix: Use errors.WrapErrorWithPrefix to add context to an error with a specified prefix. This helps in tracking where the error occurred. If the error is nil, it does nothing.
Wrapping Errors: Use errors.WrapError to combine multiple errors into one. If either error is nil, it returns the non-nil error. If both are non-nil, it wraps the new error around the original error.
Unwrapping Domain Errors: Use errors.UnwrapDomainError to extract the DomainError from an error chain, allowing for specialized handling of domain-specific errors.
Error Code Convention
Error codes follow the xyyzzz format:
x: Main category (e.g., 4 for Client Errors).yy: Subcategory (e.g., 01 for Bad Request Errors).zzz: Specific error code (e.g., 001 for a particular invalid parameter).
Example:
401001could represent an invalid username parameter.
Error Categories
Defined categories and their descriptions:
200zzz: Success201zzz: Partial Success202zzz: Accepted
400zzz: Client Errors401zzz: Bad Request402zzz: Not Found403zzz: Conflict404zzz: Unprocessable Entity
500zzz: Server Errors501zzz: Database Errors502zzz: 3rd Party Errors503zzz: Service Unavailable
900zzz: Security Errors901zzz: Unauthorized902zzz: Forbidden
The validCategories map in
categories.gomaintains the valid categories and their descriptions.
Examples
You can find a complete working example in the repository under framework/errors/example.
Real-World Examples
Ticket Reservation System - A complete microservice demonstrating error handling patterns, HTTP middleware integration, and domain-specific error types.
Best Practices
Consistency: Always define error codes and messages in a centralized place to maintain consistency.
Embedding BaseError: Ensure all custom errors embed
*errors.BaseErrorto integrate with the error handling utilities.Category Alignment: When defining new error codes, make sure they align with the predefined categories and use the correct HTTP status codes.
Avoid Manual Synchronization: Use the centralized data structures for categories and error codes to prevent inconsistencies.
Last updated