package errors import ( "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).Msg("user not found %d", userId) func Errorf(status int, format string, parts ...any) SettableError { if len(parts) == 0 { return &erf{status, format, ""} } err := fmt.Errorf(format, parts...) msg := err.Error() er := &erf{status, msg, ""} 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) type erf struct { stat int err string msg string } func (e *erf) GetStatus() 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) GetMsg() string { if e.msg == "" { return e.err } return e.msg } func (e *erf) Status(status int) SettableError { // GetStatus 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) Msg(msg string, parts ...any) SettableError { e.msg = msg if len(parts) > 0 { e.msg = fmt.Sprintf(msg, parts...) } return e } 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 }