package errors import ( "fmt" "net/http" "runtime" "strings" ) type errorWrapper interface { Error() string GetOriginalError() *error } // WrappedError holds an error wrapped with a context message type WrappedError struct { originalError *error path string messages []string } func (err WrappedError) Error() string { if len(err.messages) > 0 { retVal := fmt.Sprintf("%s: ", err.path) for _, message := range err.messages { retVal += message + "; " } return fmt.Sprintf("%s => %v", retVal, *err.originalError) } return fmt.Sprintf("%s => %v", err.path, *err.originalError) } // GetOriginalError returns the original error func (err WrappedError) GetOriginalError() *error { if err.originalError != nil { if originalError, ok := (*err.originalError).(errorWrapper); ok { return originalError.GetOriginalError() } } return err.originalError } // Wrap wraps an error with a context message func Wrap(err error, messages ...string) error { if err != nil { // get caller function path pc := make([]uintptr, 10) runtime.Callers(2, pc) funcRef := runtime.FuncForPC(pc[0]) pathArr := strings.Split(funcRef.Name(), "/") path := pathArr[len(pathArr)-1] return &WrappedError{ originalError: &err, path: path, messages: messages, } } return nil } // NewValidationError returns a ValidationError instance with the provided parameters func NewValidationError(field string, message string) *ValidationError { return &ValidationError{ Field: field, Message: message, } } // NewNullArgumentError returns a preformatted error for null arguments func NewNullArgumentError(argumentName string) *NullArgumentError { return &NullArgumentError{argumentName} } // NewApplicationError returns a ApplicationError instance func NewApplicationError(path string, message string) *ApplicationError { return &ApplicationError{ Message: message, Path: path, } } // NewNotAuthorizedError returns a NotAuthorizedError instance func NewNotAuthorizedError(message string) *NotAuthorizedError { return &NotAuthorizedError{ Message: message, } } // NewHTTPError returns a HTTPError instance func NewHTTPError(httpStatus int, message string) *HTTPError { return &HTTPError{ Status: httpStatus, Message: message, } } // NewNotFoundError returns a Not Found HTTPError instance func NewNotFoundError() *HTTPError { return NewHTTPError(http.StatusNotFound, "Not Found") } // HTTPError represents a generic HTTP error response type HTTPError struct { Status int Message string } func (e *HTTPError) Error() string { return fmt.Sprintf("%v - %s", e.Status, e.Message) } // NullArgumentError represents a error that is used to sinalize that a provided argument is null type NullArgumentError struct { ArgumentName string } func (e *NullArgumentError) Error() string { return fmt.Sprintf("Parameter %s can't be null", e.ArgumentName) } // ValidationError represents an input validation error type ValidationError struct { Field string `json:"field_name,omitempty"` Message string `json:"message,omitempty"` Errors []ValidationError `json:"errors,omitempty"` } func (e *ValidationError) Error() string { var errorList []string for _, err := range e.Errors { errorList = append(errorList, err.Error()) } output := e.Message if len(errorList) > 0 { output += fmt.Sprintf("\n - %v", strings.Join(errorList, ";\n - ")) } return fmt.Sprintf("%v: %v", e.Field, output) } // AddError adds a new validation error to the chain func (e *ValidationError) AddError(field string, message string) { e.Errors = append(e.Errors, ValidationError{ Field: field, Message: message, }) } // ApplicationError represents a common applicatino error structure type ApplicationError struct { Message string Path string } func (e *ApplicationError) Error() string { return e.Message } // NotAuthorizedError represents an access restriction error structure type NotAuthorizedError struct { Message string } func (e *NotAuthorizedError) Error() string { return e.Message }