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 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 // 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. // and fire the error status code and title based on this error code name itself.
var asErrCode ErrorCodeName var asErrCode ErrorCodeName
@ -161,13 +170,18 @@ func HandleError(ctx *context.Context, err error) bool {
return true return true
} }
for errorCodeName, errorFuncs := range errorFuncCodeMap { if handleJSONError(ctx, err) {
for _, errorFunc := range errorFuncs { return true
if errToSend := errorFunc(err); errToSend != nil { }
errorCodeName.Err(ctx, errToSend)
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) Internal.LogErr(ctx, err)
@ -335,20 +349,45 @@ func HandleAPIError(ctx *context.Context, err error) {
// Error expected and came from the external server, // Error expected and came from the external server,
// save its body so we can forward it to the end-client. // save its body so we can forward it to the end-client.
if apiErr, ok := client.GetError(err); ok { if apiErr, ok := client.GetError(err); ok {
statusCode := apiErr.Response.StatusCode handleAPIError(ctx, apiErr)
if statusCode >= 400 && statusCode < 500 {
InvalidArgument.DataWithDetails(ctx, "remote server error", "invalid client request", apiErr.Body)
} else {
Internal.Data(ctx, "remote server error", apiErr.Body)
}
// Unavailable.DataWithDetails(ctx, "remote server error", "unavailable", apiErr.Body)
return return
} }
Internal.LogErr(ctx, err) 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)
} else {
Internal.Data(ctx, "remote server error", apiErr.Body)
}
// Unavailable.DataWithDetails(ctx, "remote server error", "unavailable", apiErr.Body)
}
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
}
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 ( var (
// ErrUnexpected is the HTTP error which sent to the client // ErrUnexpected is the HTTP error which sent to the client
// when server fails to send an error, it's a fallback error. // when server fails to send an error, it's a fallback error.

View File

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