minor improvements on x/errors package, see previous commit for more

This commit is contained in:
Gerasimos (Makis) Maropoulos 2024-01-04 13:02:09 +02:00
parent 1ae4e71176
commit 8f2deb6873
No known key found for this signature in database
GPG Key ID: B9839E9CD30B7B6B
2 changed files with 72 additions and 22 deletions

View File

@ -139,6 +139,15 @@ func HandleError(ctx *context.Context, err error) bool {
return false
}
for errorCodeName, errorFuncs := range errorFuncCodeMap {
for _, errorFunc := range errorFuncs {
if errToSend := errorFunc(err); errToSend != nil {
errorCodeName.Err(ctx, errToSend)
return true
}
}
}
// 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
@ -161,13 +170,18 @@ func HandleError(ctx *context.Context, err error) bool {
return true
}
for errorCodeName, errorFuncs := range errorFuncCodeMap {
for _, errorFunc := range errorFuncs {
if errToSend := errorFunc(err); errToSend != nil {
errorCodeName.Err(ctx, errToSend)
if handleJSONError(ctx, err) {
return true
}
if vErrs, ok := AsValidationErrors(err); ok {
InvalidArgument.Data(ctx, "validation failure", vErrs)
return true
}
if apiErr, ok := client.GetError(err); ok {
handleAPIError(ctx, apiErr)
return true
}
Internal.LogErr(ctx, err)
@ -335,6 +349,16 @@ func HandleAPIError(ctx *context.Context, err error) {
// Error expected and came from the external server,
// save its body so we can forward it to the end-client.
if apiErr, ok := client.GetError(err); ok {
handleAPIError(ctx, apiErr)
return
}
Internal.LogErr(ctx, err)
}
func handleAPIError(ctx *context.Context, apiErr client.APIError) {
// Error expected and came from the external server,
// save its body so we can forward it to the end-client.
statusCode := apiErr.Response.StatusCode
if statusCode >= 400 && statusCode < 500 {
InvalidArgument.DataWithDetails(ctx, "remote server error", "invalid client request", apiErr.Body)
@ -343,10 +367,25 @@ func HandleAPIError(ctx *context.Context, err error) {
}
// Unavailable.DataWithDetails(ctx, "remote server error", "unavailable", apiErr.Body)
return
}
func handleJSONError(ctx *context.Context, err error) bool {
var syntaxErr *json.SyntaxError
if errors.As(err, &syntaxErr) {
InvalidArgument.Details(ctx, "unable to parse body", "syntax error at byte offset %d", syntaxErr.Offset)
return true
}
Internal.LogErr(ctx, err)
var unmarshalErr *json.UnmarshalTypeError
if errors.As(err, &unmarshalErr) {
InvalidArgument.Details(ctx, "unable to parse body", "unmarshal error for field %q", unmarshalErr.Field)
return true
}
return false
// else {
// InvalidArgument.Details(ctx, "unable to parse body", err.Error())
// }
}
var (

View File

@ -2,6 +2,8 @@ package errors
import (
stdContext "context"
"errors"
"io"
"net/http"
"github.com/kataras/iris/v12/context"
@ -117,10 +119,11 @@ func bindResponse[T, R any, F ResponseFunc[T, R]](ctx *context.Context, fn F, fn
var req T
switch len(fnInput) {
case 0:
err := ctx.ReadJSON(&req)
if err != nil {
var ok bool
req, ok = ReadPayload[T](ctx)
if !ok {
var resp R
return resp, !HandleError(ctx, err)
return resp, false
}
case 1:
req = fnInput[0]
@ -200,11 +203,19 @@ func ReadPayload[T any](ctx *context.Context) (T, bool) {
var payload T
err := ctx.ReadJSON(&payload)
if err != nil {
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
InvalidArgument.Details(ctx, "unable to parse body", "empty body")
return payload, false
}
if !handleJSONError(ctx, err) {
if vErrs, ok := AsValidationErrors(err); ok {
InvalidArgument.Data(ctx, "validation failure", vErrs)
} else {
InvalidArgument.Details(ctx, "unable to parse body", err.Error())
}
}
return payload, false
}