package errors import ( "fmt" "net/http" ) // ErrorType represents the type of error type ErrorType string const ( ErrorTypeValidation ErrorType = "VALIDATION_ERROR" ErrorTypeAuthorization ErrorType = "AUTHORIZATION_ERROR" ErrorTypeAuthentication ErrorType = "AUTHENTICATION_ERROR" ErrorTypeNotFound ErrorType = "NOT_FOUND" ErrorTypeConflict ErrorType = "CONFLICT" ErrorTypeInternal ErrorType = "INTERNAL_ERROR" ErrorTypeBadRequest ErrorType = "BAD_REQUEST" ) // AppError represents an application error type AppError struct { Type ErrorType `json:"type"` Message string `json:"message"` Detail string `json:"detail,omitempty"` Field string `json:"field,omitempty"` Code int `json:"-"` Err error `json:"-"` } func (e *AppError) Error() string { if e.Detail != "" { return fmt.Sprintf("%s: %s (%s)", e.Type, e.Message, e.Detail) } return fmt.Sprintf("%s: %s", e.Type, e.Message) } func (e *AppError) Unwrap() error { return e.Err } // Error constructors func NewValidationError(message, field string) *AppError { return &AppError{ Type: ErrorTypeValidation, Message: message, Field: field, Code: http.StatusBadRequest, } } func NewAuthorizationError(message string) *AppError { return &AppError{ Type: ErrorTypeAuthorization, Message: message, Code: http.StatusForbidden, } } func NewAuthenticationError(message string) *AppError { return &AppError{ Type: ErrorTypeAuthentication, Message: message, Code: http.StatusUnauthorized, } } func NewNotFoundError(resource, id string) *AppError { return &AppError{ Type: ErrorTypeNotFound, Message: fmt.Sprintf("%s not found", resource), Detail: fmt.Sprintf("ID: %s", id), Code: http.StatusNotFound, } } func NewConflictError(message, detail string) *AppError { return &AppError{ Type: ErrorTypeConflict, Message: message, Detail: detail, Code: http.StatusConflict, } } func NewInternalError(message string, err error) *AppError { return &AppError{ Type: ErrorTypeInternal, Message: message, Detail: err.Error(), Code: http.StatusInternalServerError, Err: err, } } // Error type checks func IsNotFound(err error) bool { if err == nil { return false } if e, ok := err.(*AppError); ok { return e.Type == ErrorTypeNotFound } return false } func IsValidation(err error) bool { if err == nil { return false } if e, ok := err.(*AppError); ok { return e.Type == ErrorTypeValidation } return false } func IsAuthorization(err error) bool { if err == nil { return false } if e, ok := err.(*AppError); ok { return e.Type == ErrorTypeAuthorization || e.Type == ErrorTypeAuthentication } return false } // WithDetail adds detail to an existing error func WithDetail(err *AppError, detail string) *AppError { if err == nil { return nil } err.Detail = detail return err } // WithField adds a field name to an existing error func WithField(err *AppError, field string) *AppError { if err == nil { return nil } err.Field = field return err }