diff --git a/HISTORY.md b/HISTORY.md index 7309fb9e..af2c2de2 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -26,7 +26,7 @@ Changes apply to `main` branch. - Add `x/jsonx.GetSimpleDateRange(date, jsonx.WeekRange, time.Monday, time.Sunday)` which returns all dates between the given range and start/end weekday values for WeekRange. - Add `x/timex.GetMonthDays` and `x/timex.GetMonthEnd` functions. - Add `iris.CookieDomain` and `iris.CookieOverride` cookie options to handle [#2309](https://github.com/kataras/iris/issues/2309). -- New `x/errors.ErrorCodeName.MapErrorFunc`, `x/errors.ErrorCodeName.MapErrors` methods and `x/errors.HandleError` package-level function. +- New `x/errors.ErrorCodeName.MapErrorFunc`, `x/errors.ErrorCodeName.MapErrors`, `x/errors.ErrorCodeName.Wrap` methods and `x/errors.HandleError` package-level function. # Sun, 05 Nov 2023 | v12.2.8 diff --git a/x/errors/errors.go b/x/errors/errors.go index deb98c6f..57f5d9f2 100644 --- a/x/errors/errors.go +++ b/x/errors/errors.go @@ -2,6 +2,7 @@ package errors import ( "encoding/json" + "errors" "fmt" "net/http" @@ -134,6 +135,28 @@ func HandleError(ctx *context.Context, err error) bool { return false } + // Unwrap and collect the errors slice so the error result doesn't contain the ErrorCodeName type + // and fire the error status code and title based on this error code name itself. + var asErrCode ErrorCodeName + if As(err, &asErrCode) { + if unwrapJoined, ok := err.(joinedErrors); ok { + errs := unwrapJoined.Unwrap() + errsToKeep := make([]error, 0, len(errs)-1) + for _, src := range errs { + if _, isErrorCodeName := src.(ErrorCodeName); !isErrorCodeName { + errsToKeep = append(errsToKeep, src) + } + } + + if len(errsToKeep) > 0 { + err = errors.Join(errsToKeep...) + } + } + + asErrCode.Err(ctx, err) + return true + } + for errorCodeName, errorFuncs := range errorFuncCodeMap { for _, errorFunc := range errorFuncs { if errToSend := errorFunc(err); errToSend != nil { @@ -147,6 +170,24 @@ func HandleError(ctx *context.Context, err error) bool { return true } +// Error returns an empty string, it is only declared as a method of ErrorCodeName type in order +// to be a compatible error to be joined within other errors: +// +// err = fmt.Errorf("%w%w", errors.InvalidArgument, err) OR +// err = errors.InvalidArgument.Wrap(err) +func (e ErrorCodeName) Error() string { + return "" +} + +type joinedErrors interface{ Unwrap() []error } + +// Wrap wraps the given error with this ErrorCodeName. +// It calls the standard errors.Join package-level function. +// See HandleError function for more. +func (e ErrorCodeName) Wrap(err error) error { + return errors.Join(e, err) +} + // MapErrorFunc registers a function which will validate the incoming error and // return the same error or overriden in order to be sent to the client, wrapped by this ErrorCodeName "e". //