Basic Examples¶
This guide provides practical examples of common error handling scenarios using ewrap. Each example demonstrates a specific feature or pattern, helping you understand how to use the package effectively.
Simple Error Creation and Handling¶
Let's start with basic error creation and handling:
package main
import (
"context"
"fmt"
"github.com/hyp3rd/ewrap/pkg/ewrap"
)
func main() {
if err := processUserRegistration("john.doe@example.com"); err != nil {
fmt.Printf("Registration failed: %v\n", err)
return
}
fmt.Println("Registration successful")
}
func processUserRegistration(email string) error {
// Create a context for the operation
ctx := context.Background()
// Validate email
if err := validateEmail(email); err != nil {
return ewrap.Wrap(err, "email validation failed",
ewrap.WithContext(ctx, ewrap.ErrorTypeValidation, ewrap.SeverityError))
}
// Create user in database
if err := createUser(email); err != nil {
return ewrap.Wrap(err, "user creation failed",
ewrap.WithContext(ctx, ewrap.ErrorTypeDatabase, ewrap.SeverityError))
}
return nil
}
func validateEmail(email string) error {
if !strings.Contains(email, "@") {
return ewrap.New("invalid email format")
}
return nil
}
func createUser(email string) error {
// Simulate database operation
return nil
}
Error Groups for Multiple Validations¶
Here's how to collect multiple validation errors:
type User struct {
Email string
Password string
Age int
Username string
}
func validateUser(ctx context.Context, user User) error {
// Get an error group from the pool
pool := ewrap.NewErrorGroupPool(4)
eg := pool.Get()
defer eg.Release()
// Validate email
if err := validateEmail(user.Email); err != nil {
eg.Add(ewrap.Wrap(err, "invalid email",
ewrap.WithContext(ctx, ewrap.ErrorTypeValidation, ewrap.SeverityError)))
}
// Validate password
if len(user.Password) < 8 {
eg.Add(ewrap.New("password too short",
ewrap.WithContext(ctx, ewrap.ErrorTypeValidation, ewrap.SeverityError)).
WithMetadata("min_length", 8))
}
// Validate age
if user.Age < 18 {
eg.Add(ewrap.New("user must be 18 or older",
ewrap.WithContext(ctx, ewrap.ErrorTypeValidation, ewrap.SeverityError)).
WithMetadata("provided_age", user.Age))
}
return eg.Error()
}
Logging Integration¶
Example showing basic logging integration:
type AppLogger struct {
logger *zap.Logger
}
func (l *AppLogger) Error(msg string, keysAndValues ...interface{}) {
l.logger.Error(msg, convertToZapFields(keysAndValues...)...)
}
func (l *AppLogger) Debug(msg string, keysAndValues ...interface{}) {
l.logger.Debug(msg, convertToZapFields(keysAndValues...)...)
}
func (l *AppLogger) Info(msg string, keysAndValues ...interface{}) {
l.logger.Info(msg, convertToZapFields(keysAndValues...)...)
}
func processWithLogging(ctx context.Context, data []byte) error {
logger := &AppLogger{logger: zapLogger}
err := processData(data)
if err != nil {
return ewrap.Wrap(err, "data processing failed",
ewrap.WithContext(ctx, ewrap.ErrorTypeInternal, ewrap.SeverityError),
ewrap.WithLogger(logger))
}
return nil
}
HTTP Handler Example¶
Using ewrap in an HTTP handler:
func handleUserRegistration(w http.ResponseWriter, r *http.Request) {
// Create request context with ID
ctx := r.Context()
requestID := generateRequestID()
ctx = context.WithValue(ctx, "request_id", requestID)
var user User
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
respondWithError(w, ewrap.Wrap(err, "invalid request body",
ewrap.WithContext(ctx, ewrap.ErrorTypeValidation, ewrap.SeverityError)))
return
}
if err := validateUser(ctx, user); err != nil {
respondWithError(w, err)
return
}
if err := createUser(ctx, user); err != nil {
respondWithError(w, err)
return
}
respondWithJSON(w, http.StatusCreated, map[string]string{
"message": "user created successfully",
})
}
func respondWithError(w http.ResponseWriter, err error) {
if wrappedErr, ok := err.(*ewrap.Error); ok {
// Convert error to API response
response := ErrorResponse{
Message: wrappedErr.Error(),
Code: getErrorCode(wrappedErr),
Details: getErrorDetails(wrappedErr),
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(getHTTPStatus(wrappedErr))
json.NewEncoder(w).Encode(response)
} else {
// Handle unwrapped errors
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"message": "internal server error",
})
}
}
Database Operations¶
Example showing database error handling:
func getUserByID(ctx context.Context, userID string) (*User, error) {
var user User
err := db.QueryRow("SELECT * FROM users WHERE id = $1", userID).Scan(&user)
switch {
case err == sql.ErrNoRows:
return nil, ewrap.New("user not found",
ewrap.WithContext(ctx, ewrap.ErrorTypeNotFound, ewrap.SeverityWarning)).
WithMetadata("user_id", userID)
case err != nil:
return nil, ewrap.Wrap(err, "database query failed",
ewrap.WithContext(ctx, ewrap.ErrorTypeDatabase, ewrap.SeverityError)).
WithMetadata("user_id", userID)
}
return &user, nil
}
Cleanup and Deferred Operations¶
Example showing error handling with cleanup:
func processFile(ctx context.Context, path string) error {
file, err := os.Open(path)
if err != nil {
return ewrap.Wrap(err, "failed to open file",
ewrap.WithContext(ctx, ewrap.ErrorTypeInternal, ewrap.SeverityError))
}
defer func() {
if closeErr := file.Close(); closeErr != nil {
err = ewrap.Wrap(closeErr, "failed to close file",
ewrap.WithContext(ctx, ewrap.ErrorTypeInternal, ewrap.SeverityWarning))
}
}()
// Process file...
return nil
}