package apperror import ( "bytes" "encoding/json" "errors" "fmt" ) type StatusCoder interface { error Caller StatusCode() int } type Caller interface { SourceLocation() SourceLocation } type JSONResponder interface { error Caller JSONResponse() (int, interface{}) JSONDetails() map[string]interface{} } type ErrorAborter interface { error Caller AbortError() (int, error) } type Redirecter interface { error Redirect() (int, string, string) } type ErrorCoder interface { ErrorCode() string } // ErrorChain traverses the error chain by unwarpping, and returns a string func ErrorChain(err error) string { var buf bytes.Buffer for err != nil { switch e := err.(type) { case *StatusError: fmt.Fprintf(&buf, "[%v]: %s", e.code, e.Error()) case *JSONError: fmt.Fprintf(&buf, "[%v]: %s", e.code, e.Error()) case *AbortError: fmt.Fprintf(&buf, "[%v]: %s", e.code, e.Error()) case RedirectError: code, loc, _ := e.Redirect() fmt.Fprintf(&buf, "[%v]: redirect to: %s", code, loc) default: //fmt.Fprintf(&buf, "%s", e.Error()) } err = errors.Unwrap(err) } return buf.String() } // ErrorCode returns the error code of the AppError. // Returns an empty string for any other error type. func ErrorCode(err error) string { if errCoder, ok := err.(ErrorCoder); ok { return errCoder.ErrorCode() } return "" } type SourceLocation struct { File string `json:"file,omitempty"` Func string `json:"function,omitempty"` Line int `json:"line,omitempty"` } func (sl SourceLocation) ToMap() map[string]interface{} { res := make(map[string]interface{}) bytes, err := json.Marshal(sl) if err != nil { return nil } err = json.Unmarshal(bytes, &res) if err != nil { return nil } return res }