Skip to content

Commit 8b7b742

Browse files
committed
Added initial code
1 parent 6b3015f commit 8b7b742

File tree

7 files changed

+600
-1
lines changed

7 files changed

+600
-1
lines changed

README.md

Lines changed: 232 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,233 @@
1-
# app-error
1+
# App Error - Structured Error Handling for Go Applications
2+
23
A comprehensive and flexible error handling package designed for Go applications that need structured, traceable, and contextual error management. This package provides a robust foundation for building reliable services with proper error propagation, logging, and debugging capabilities.
4+
5+
## Overview
6+
7+
App Error is built around the principle that effective error handling requires more than just error messages. Modern applications need structured errors that carry context, support tracing, provide HTTP status mappings, and enable proper debugging workflows. This package delivers all of these capabilities while maintaining simplicity and performance.
8+
9+
## Key Features
10+
11+
### Structured Error Management
12+
- **Hierarchical Error Structure**: Combines actual errors with custom error definitions and metadata
13+
- **Error Code Management**: Support for primary error codes and error code chains
14+
- **HTTP Status Integration**: Automatic mapping between errors and appropriate HTTP status codes
15+
- **Flexible Metadata**: Attach arbitrary data to errors for debugging and logging purposes
16+
17+
### Context-Aware Error Tracing
18+
- **Trace Logging**: Automatic trace collection as errors propagate through your application
19+
- **Context Integration**: Seamless integration with Go's context package for request tracing
20+
- **Error Evolution Tracking**: Monitor how errors change as they move through different layers
21+
22+
### Custom Error Definitions
23+
- **Predefined Error Types**: Create reusable error definitions with codes, messages, and retry policies
24+
- **Dynamic Error Creation**: Build errors on-the-fly when predefined types aren't sufficient
25+
- **Retry Policy Support**: Mark errors as retryable or non-retryable for client guidance
26+
27+
### Developer-Friendly API
28+
- **Method Chaining**: Fluent interface for building complex error structures
29+
- **Immutable Operations**: Safe error manipulation without side effects
30+
- **Type Safety**: Strong typing throughout the API to prevent common mistakes
31+
32+
## Core Components
33+
34+
### AppError Structure
35+
The central error type that encapsulates all error information including the underlying error, custom error details, error code chains, HTTP status codes, and additional metadata.
36+
37+
### CustomErr Structure
38+
Represents predefined error templates with error codes, human-readable messages, and retry policies. These serve as blueprints for creating consistent error responses across your application.
39+
40+
### TraceMeta Structure
41+
Manages error tracing information including trace logs, error evolution history, and identifier mappings for debugging and monitoring purposes.
42+
43+
## Installation
44+
45+
Add the package to your Go module:
46+
47+
```
48+
go get github.com/piyushkumar96/app-error
49+
```
50+
51+
Import the package in your Go files:
52+
53+
```
54+
import ae "github.com/piyushkumar96/app-error"
55+
```
56+
57+
## API Documentation
58+
59+
### Creating Custom Error Definitions
60+
61+
**GetCustomErr Function**
62+
Creates a new custom error definition with the specified error code, message, and retry policy. This function is typically used to define error constants that can be reused throughout your application.
63+
64+
Parameters:
65+
- `code`: Unique error identifier (string)
66+
- `message`: Human-readable error description (string)
67+
- `retryable`: Whether the error condition can be retried (boolean)
68+
69+
Returns a CustomErr pointer that can be used with GetAppErr.
70+
71+
### Creating Application Errors
72+
73+
**GetAppErr Function**
74+
Constructs a complete application error by combining an actual error with custom error details, HTTP status code, and optional metadata.
75+
76+
Parameters:
77+
- `ctx`: Request context for tracing (context.Context)
78+
- `err`: The underlying error that occurred (error)
79+
- `customErr`: Custom error definition (*CustomErr)
80+
- `httpCode`: Appropriate HTTP status code (int)
81+
- `meta`: Optional metadata (variadic interface{})
82+
83+
Returns an AppError pointer with all error information properly structured.
84+
85+
### AppError Methods
86+
87+
**Error Retrieval Methods**
88+
- `Error()`: Returns the underlying error message (implements error interface)
89+
- `GetErr()`: Retrieves the actual underlying error
90+
- `GetMsg()`: Returns the custom error message
91+
- `GetErrCode()`: Gets the primary error code
92+
- `GetErrCodes()`: Returns all error codes in the chain
93+
- `GetHTTPCode()`: Retrieves the HTTP status code
94+
- `GetData()`: Accesses attached metadata
95+
96+
**Error Modification Methods**
97+
- `SetErr(error)`: Updates the underlying error
98+
- `SetMsg(string)`: Modifies the custom error message
99+
- `SetErrCode(string)`: Changes the primary error code
100+
- `SetHTTPCode(int)`: Updates the HTTP status code
101+
- `SetData(interface{})`: Attaches or updates metadata
102+
- `AddErrCode(string)`: Appends an error code to the chain
103+
104+
All modification methods return the AppError instance to enable method chaining.
105+
106+
### Context and Tracing
107+
108+
**AddTraceLog Function**
109+
Adds error information to the trace log stored in the request context. This function automatically captures error details for debugging and monitoring purposes.
110+
111+
Parameters:
112+
- `ctx`: Request context containing trace information (context.Context)
113+
- `errorMsg`: Error message to add to the trace (string)
114+
115+
Returns the updated TraceMeta or nil if context is invalid.
116+
117+
## Usage Patterns
118+
119+
### Basic Error Creation
120+
Start with a simple error and enhance it with custom error details and appropriate HTTP status codes. This pattern is suitable for straightforward error scenarios where you need structured error information.
121+
122+
### Error Evolution and Chaining
123+
Begin with a general error and progressively add more specific error codes as your understanding of the problem improves. This pattern is excellent for debugging complex issues and providing detailed error context.
124+
125+
### Predefined Error Constants
126+
Define common errors as package-level constants to ensure consistency across your application. This approach reduces duplication and provides a centralized error catalog.
127+
128+
### Metadata Attachment
129+
Include additional debugging information such as request parameters, system state, or configuration details that can help with troubleshooting.
130+
131+
### Retryable Error Handling
132+
Use the retry policy feature to guide client behavior, especially in distributed systems where temporary failures are common.
133+
134+
## Best Practices
135+
136+
### Error Code Conventions
137+
- Use consistent prefixes for different service layers or modules
138+
- Include severity levels in error codes when appropriate
139+
- Maintain a centralized registry of error codes to prevent conflicts
140+
- Use semantic versioning principles for error code evolution
141+
142+
### Message Guidelines
143+
- Write clear, actionable error messages for end users
144+
- Include technical details in metadata rather than user-facing messages
145+
- Use consistent language and terminology across all error messages
146+
- Avoid exposing internal implementation details in error messages
147+
148+
### HTTP Status Code Mapping
149+
- Follow HTTP status code specifications strictly
150+
- Use 4xx codes for client errors and 5xx codes for server errors
151+
- Be consistent in status code usage across similar error types
152+
- Consider the impact on API consumers when choosing status codes
153+
154+
### Context Management
155+
- Always pass context through your error handling chain
156+
- Use context cancellation to prevent resource leaks in error scenarios
157+
- Store request-specific information in context for error tracing
158+
- Avoid storing large objects in context to prevent memory issues
159+
160+
### Metadata Usage
161+
- Include only essential debugging information in metadata
162+
- Use structured data formats for complex metadata
163+
- Consider the performance impact of large metadata objects
164+
- Sanitize sensitive information before including in metadata
165+
166+
### Testing Considerations
167+
- Test error scenarios as thoroughly as success cases
168+
- Verify error code consistency across different code paths
169+
- Validate HTTP status code mappings in integration tests
170+
- Mock external dependencies to test error handling paths
171+
172+
## Performance Considerations
173+
174+
### Memory Management
175+
The package is designed to minimize memory allocations during error creation and manipulation. Error objects are lightweight and metadata is stored efficiently.
176+
177+
### Concurrency Safety
178+
All operations on error objects are safe for concurrent access. Context-based tracing handles concurrent requests appropriately without race conditions.
179+
180+
### Trace Overhead
181+
Error tracing adds minimal overhead to request processing. Trace data is collected efficiently and stored in a compact format.
182+
183+
## Error Handling Strategies
184+
185+
### Layered Error Handling
186+
Structure your application in layers with each layer adding appropriate context to errors as they propagate upward. Lower layers focus on technical details while upper layers add business context.
187+
188+
### Circuit Breaker Integration
189+
Use the retry policy feature to integrate with circuit breakers and other reliability patterns. Mark errors as retryable or non-retryable based on the underlying failure type.
190+
191+
### Graceful Degradation
192+
Design error responses that allow clients to degrade gracefully when certain features are unavailable. Use appropriate HTTP status codes and error messages to guide client behavior.
193+
194+
### Monitoring and Alerting
195+
Leverage error codes and metadata for monitoring system health. Set up alerting based on error code patterns and frequencies.
196+
197+
## Contributing
198+
199+
We welcome contributions to improve this package. Please follow these guidelines:
200+
201+
### Development Setup
202+
- Ensure Go 1.20 or later is installed
203+
- Run tests before submitting changes
204+
- Follow Go coding conventions and best practices
205+
- Add appropriate documentation for new features
206+
207+
### Testing Requirements
208+
- Write unit tests for all new functionality
209+
- Ensure existing tests pass after changes
210+
- Add integration tests for complex features
211+
- Include edge case testing for error scenarios
212+
213+
### Documentation Updates
214+
- Update this README for significant changes
215+
- Add inline code documentation for new functions
216+
- Include usage examples for new features
217+
- Update API documentation as needed
218+
219+
## License
220+
221+
This project is licensed under the terms specified in the LICENSE file. Please review the license before using this package in your projects.
222+
223+
## Support and Feedback
224+
225+
For questions, bug reports, or feature requests, please use the appropriate channels provided by your organization. We value your feedback and contributions to making this package better.
226+
227+
## Versioning
228+
229+
This package follows semantic versioning principles. Check the version tags for compatibility information and upgrade guidance.
230+
231+
## Changelog
232+
233+
Significant changes and new features are documented in version releases. Review the changelog when upgrading to understand breaking changes and new capabilities.

appError.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package errors
2+
3+
import (
4+
"context"
5+
)
6+
7+
// AppError represents a structured error with additional metadata
8+
type AppError struct {
9+
ActualErr error // The actual underlying error
10+
CustomErr *CustomErr // Custom error details (code, message, etc.)
11+
ErrorCodes []string // All error codes encountered during execution
12+
httpCode int // Corresponding HTTP error code
13+
data interface{} // Additional data to include in the error response
14+
}
15+
16+
// Error implements the error interface, returning the error message
17+
func (e *AppError) Error() string {
18+
if e.ActualErr == nil {
19+
return ""
20+
}
21+
return e.ActualErr.Error()
22+
}
23+
24+
// GetErr retrieves the underlying error
25+
func (e *AppError) GetErr() error {
26+
return e.ActualErr
27+
}
28+
29+
// SetErr sets the underlying error and returns it
30+
func (e *AppError) SetErr(err error) error {
31+
e.ActualErr = err
32+
return e.ActualErr
33+
}
34+
35+
// GetMsg retrieves the custom error message
36+
func (e *AppError) GetMsg() string {
37+
return e.CustomErr.Message
38+
}
39+
40+
// SetMsg updates the custom error message and returns the AppError
41+
func (e *AppError) SetMsg(msg string) *AppError {
42+
e.CustomErr.Message = msg
43+
return e
44+
}
45+
46+
// GetHTTPCode retrieves the HTTP status code
47+
func (e *AppError) GetHTTPCode() int {
48+
return e.httpCode
49+
}
50+
51+
// SetHTTPCode updates the HTTP status code and returns the AppError
52+
func (e *AppError) SetHTTPCode(httpCode int) *AppError {
53+
e.httpCode = httpCode
54+
return e
55+
}
56+
57+
// GetErrCode retrieves the primary error code
58+
func (e *AppError) GetErrCode() string {
59+
return e.CustomErr.Code
60+
}
61+
62+
// SetErrCode updates the primary error code and returns the AppError
63+
func (e *AppError) SetErrCode(code string) *AppError {
64+
e.CustomErr.Code = code
65+
return e
66+
}
67+
68+
// GetErrCodes retrieves the list of all error codes
69+
func (e *AppError) GetErrCodes() []string {
70+
return e.ErrorCodes
71+
}
72+
73+
// AddErrCode appends an error code to the list and updates the primary code
74+
func (e *AppError) AddErrCode(errorCode string) *AppError {
75+
if errorCode != "" {
76+
e.CustomErr.Code = errorCode
77+
e.ErrorCodes = append(e.ErrorCodes, errorCode)
78+
}
79+
return e
80+
}
81+
82+
// GetData retrieves the additional metadata associated with the error
83+
func (e *AppError) GetData() interface{} {
84+
return e.data
85+
}
86+
87+
// SetData updates the metadata and returns the AppError
88+
func (e *AppError) SetData(data interface{}) *AppError {
89+
e.data = data
90+
return e
91+
}
92+
93+
// GetAppErr creates a new instance of AppError
94+
func GetAppErr(ctx context.Context, err error, customErr *CustomErr, httpCode int, meta ...interface{}) *AppError {
95+
// Log the error trace for debugging
96+
AddTraceLog(ctx, err.Error())
97+
98+
// Initialize the AppError structure
99+
appErr := &AppError{
100+
ActualErr: err,
101+
CustomErr: &CustomErr{},
102+
httpCode: httpCode,
103+
ErrorCodes: []string{},
104+
}
105+
106+
// Assign metadata if provided
107+
if len(meta) > 0 {
108+
appErr.data = meta[0]
109+
}
110+
111+
// Populate custom error details if provided
112+
if customErr != nil {
113+
appErr.CustomErr.Code = customErr.Code
114+
appErr.CustomErr.Message = customErr.Message
115+
appErr.ErrorCodes = append(appErr.ErrorCodes, customErr.Code)
116+
}
117+
118+
return appErr
119+
}

constants/constants.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package errors
2+
3+
const (
4+
TraceMetaKey = "TraceMeta"
5+
)

context.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package errors
2+
3+
import (
4+
"context"
5+
6+
c "github.com/piyushkumar96/app-error/constants"
7+
)
8+
9+
type TraceMeta struct {
10+
Trace []string
11+
Error []string
12+
IdentifierMappings map[string]interface{}
13+
}
14+
15+
func AddTraceLog(ctx context.Context, errorMsg string) *TraceMeta {
16+
if ctx == nil {
17+
return nil
18+
}
19+
20+
trace := ctx.Value(c.TraceMetaKey)
21+
traceMeta, ok := trace.(*TraceMeta)
22+
if !ok {
23+
return nil
24+
}
25+
26+
traceMeta.Error = append(traceMeta.Error, errorMsg)
27+
return traceMeta
28+
}

0 commit comments

Comments
 (0)