responsable-errors/errorf.go

119 lines
2.3 KiB
Go
Raw Permalink Normal View History

2024-01-17 10:58:39 -06:00
package errors
2024-01-17 15:51:28 -06:00
import (
2024-01-21 13:50:13 -06:00
"encoding/json"
2024-01-17 15:51:28 -06:00
"fmt"
"net/http"
)
2024-01-17 10:58:39 -06:00
2024-01-17 15:51:28 -06:00
// Returns a SettableError formatted from the message, with the specified status.
2024-01-17 10:58:39 -06:00
// 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.
2024-01-17 15:51:28 -06:00
//
// 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)
2024-01-17 15:51:28 -06:00
func Errorf(status int, format string, parts ...any) SettableError {
2024-01-21 13:50:13 -06:00
meta := make(map[string]any)
2024-01-17 15:51:28 -06:00
if len(parts) == 0 {
2024-01-21 13:50:13 -06:00
return &erf{status, format, "", meta}
2024-01-17 15:51:28 -06:00
}
2024-01-17 10:58:39 -06:00
err := fmt.Errorf(format, parts...)
msg := err.Error()
2024-01-21 13:50:13 -06:00
er := &erf{status, msg, "", meta}
2024-01-17 10:58:39 -06:00
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)
2024-01-17 15:51:28 -06:00
var _ SettableError = new(erf)
2024-01-21 13:50:13 -06:00
var _ json.Marshaler = new(erf)
2024-01-17 10:58:39 -06:00
type erf struct {
stat int
2024-01-17 15:51:28 -06:00
err string
2024-01-17 10:58:39 -06:00
msg string
2024-01-21 13:50:13 -06:00
meta map[string]any
2024-01-17 10:58:39 -06:00
}
func (e *erf) Status() int {
2024-01-17 15:51:28 -06:00
if e.stat < http.StatusContinue || e.stat >= 600 {
e.stat = http.StatusInternalServerError
}
2024-01-17 10:58:39 -06:00
return e.stat
}
func (e *erf) Error() string {
2024-01-17 15:51:28 -06:00
return e.err
2024-01-17 10:58:39 -06:00
}
func (e *erf) Msg() string {
2024-01-17 15:51:28 -06:00
if e.msg == "" {
return e.err
}
2024-01-17 10:58:39 -06:00
return e.msg
}
func (e *erf) SetStatus(status int) SettableError {
// Status already handles invalid values, so we'll just ignore this.
2024-01-17 15:51:28 -06:00
if status < http.StatusContinue || status >= 600 {
return e
}
e.stat = status
return e
}
func (e *erf) SetMsg(msg string, parts ...any) SettableError {
2024-01-17 15:51:28 -06:00
e.msg = msg
if len(parts) > 0 {
e.msg = fmt.Sprintf(msg, parts...)
}
return e
}
2024-01-21 13:50:13 -06:00
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())
}
2024-01-17 10:58:39 -06:00
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
}