package errors import ( "encoding/json" "fmt" "net/http" ) // Returns a SettableError formatted from the message, with the specified status. // Errorf passes the heavy lifting off to fmt.Errorf, and returns a similar error. // If one error is passed in the format, this will return an UnwrappableError. // If more than one error is passed in the format, this will return an UnwrappableErrors. // // The Msg method may also be formatted. // // If you want a different user message, use Msg, such as: // // err := errors.Errorf(http.StatusNotFound, "%w", sqlError).SetMsg("user not found %d", userId) func Errorf(status int, format string, parts ...any) SettableError { meta := make(map[string]any) if len(parts) == 0 { return &erf{status, format, "", meta} } err := fmt.Errorf(format, parts...) msg := err.Error() er := &erf{status, msg, "", meta} if we, ok := err.(wrappedError); ok { return &wrapErr{er, we.Unwrap()} } if wes, ok := err.(wrappedErrors); ok { return &wrapErrs{er, wes.Unwrap()} } return er } var _ ResponsableError = new(erf) var _ SettableError = new(erf) var _ json.Marshaler = new(erf) type erf struct { stat int err string msg string meta map[string]any } func (e *erf) Status() int { if e.stat < http.StatusContinue || e.stat >= 600 { e.stat = http.StatusInternalServerError } return e.stat } func (e *erf) Error() string { return e.err } func (e *erf) Msg() string { if e.msg == "" { return e.err } return e.msg } func (e *erf) SetStatus(status int) SettableError { // Status already handles invalid values, so we'll just ignore this. if status < http.StatusContinue || status >= 600 { return e } e.stat = status return e } func (e *erf) SetMsg(msg string, parts ...any) SettableError { e.msg = msg if len(parts) > 0 { e.msg = fmt.Sprintf(msg, parts...) } return e } func (e *erf) SetField(field string, value any) SettableError { e.meta[field] = value return e } func (e *erf) JSON() any { m := e.meta m["error"] = e.Msg() return m } func (e *erf) MarshalJSON() ([]byte, error) { return json.Marshal(e.JSON()) } var _ UnwrappableError = new(wrapErr) type wrapErr struct { *erf err error } func (e *wrapErr) Unwrap() error { return e.err } var _ UnwrappableErrors = new(wrapErrs) type wrapErrs struct { *erf errs []error } func (e *wrapErrs) Unwrap() []error { return e.errs }