From 9726827706004a610a53a70ee649512b63945abf Mon Sep 17 00:00:00 2001 From: sam Date: Wed, 27 Dec 2023 01:44:41 +0100 Subject: [PATCH] improve parse errors, they now return type errors, no field name though because that's broken for some reason --- backend/routes/v2/admin/user_action.go | 20 ++-------- backend/server/error_v2.go | 52 ++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 17 deletions(-) diff --git a/backend/routes/v2/admin/user_action.go b/backend/routes/v2/admin/user_action.go index ee079c9..90e4569 100644 --- a/backend/routes/v2/admin/user_action.go +++ b/backend/routes/v2/admin/user_action.go @@ -1,11 +1,8 @@ package admin import ( - "encoding/json" "net/http" - "reflect" - "codeberg.org/pronounscc/pronouns.cc/backend/log" "codeberg.org/pronounscc/pronouns.cc/backend/server" "github.com/aarondl/opt/omit" "github.com/go-chi/render" @@ -68,22 +65,11 @@ func (s *Server) UserAction(w http.ResponseWriter, r *http.Request) (err error) ctx := r.Context() claims, _ := server.ClaimsFromContext(ctx) - var req UserActionRequest - err = json.NewDecoder(r.Body).Decode(&req) + req, err := server.Decode[UserActionRequest](r) if err != nil { - // TODO: figure out why this isn't working - log.Debug(reflect.TypeOf(err).String()) - log.Debugf("%#v", err) - log.Debugf("%T", err) - if pe, ok := err.(*json.UnmarshalTypeError); ok { - log.Debugf("value = %q, field = %q\n", pe.Value, pe.Field) - } else { - log.Debugf("type assertion for %T to *json.UnmarshalTypeError failed", err) - } - - return server.NewV2Error(server.ErrBadRequest, "") + return err } - + // validate input if errs := req.Validate(); len(errs) != 0 { return server.NewV2Error(server.ErrBadRequest, "", errs...) } diff --git a/backend/server/error_v2.go b/backend/server/error_v2.go index ac6474d..e413c54 100644 --- a/backend/server/error_v2.go +++ b/backend/server/error_v2.go @@ -1,8 +1,12 @@ package server import ( + "encoding/json" "fmt" + "io" + "net/http" + json2 "github.com/aarondl/json" "github.com/getsentry/sentry-go" ) @@ -58,6 +62,9 @@ type ModelParseError struct { ExpectedValues []any `json:"expected_values,omitempty"` ActualValue any `json:"actual_value,omitempty"` + ExpectedType string `json:"expected_type,omitempty"` + ActualType string `json:"actual_type,omitempty"` + Key string `json:"-"` } @@ -82,3 +89,48 @@ func NewModelParseErrorWithValues(key, message string, expectedValues []any, act ActualValue: actualValue, } } + +func ParseJSONError(err error) *ModelParseError { + switch pe := err.(type) { + case *json.UnmarshalTypeError: + key := pe.Field + if key == "" { + key = "parse" + } + + return &ModelParseError{ + Key: key, + ExpectedType: pe.Type.String(), + ActualType: pe.Value, + } + case *json2.UnmarshalTypeError: + key := pe.Field + if key == "" { + key = "parse" + } + + return &ModelParseError{ + Key: key, + ExpectedType: pe.Type.String(), + ActualType: pe.Value, + } + } + + return nil +} + +func Decode[T any](r *http.Request) (T, error) { + var t T + + b, _ := io.ReadAll(r.Body) + err := json.Unmarshal(b, &t) + // err := render.Decode(r, &t) + if err != nil { + pe := ParseJSONError(err) + if pe != nil { + return t, NewV2Error(ErrBadRequest, "", *pe) + } + return t, NewV2Error(ErrBadRequest, "") + } + return t, nil +}