diff --git a/internal/server/form.go b/internal/server/form.go index 4602c4b..056f18c 100644 --- a/internal/server/form.go +++ b/internal/server/form.go @@ -1,7 +1,13 @@ // test package server -import "git.runcible.io/learning/ratchet/internal/validator" +import ( + "errors" + "net/http" + + "git.runcible.io/learning/ratchet/internal/validator" + "github.com/go-playground/form/v4" +) // Define a snippetCreateForm struct to represent the form data and validation // errors for the form fields. Note that all the struct fields are deliberately @@ -25,3 +31,23 @@ type snippetCreateForm struct { Expires int `form:"expires"` validator.Validator `form:"-"` } + +func decodePostForm(r *http.Request, fd *form.Decoder, dst any) error { + err := r.ParseForm() + if err != nil { + return err + } + + err = fd.Decode(dst, r.PostForm) + if err != nil { + var invalidDecoderError *form.InvalidDecoderError + + if errors.As(err, &invalidDecoderError) { + // if called in the handler, recovery middleware + // will log and send 500 response back + panic(err) + } + return err + } + return nil +} diff --git a/internal/server/handlers.go b/internal/server/handlers.go index 4cd6e13..8b514e5 100644 --- a/internal/server/handlers.go +++ b/internal/server/handlers.go @@ -174,11 +174,15 @@ func handleSnippetCreatePost(logger *slog.Logger, tc *TemplateCache, formDecoder return } + // initializes the struct with zero values. So &form is non-nil var form snippetCreateForm // AUTOMATIC FORM PROCESSING - - err = formDecoder.Decode(&form, r.PostForm) + // When we call app.formDecoder.Decode() it requires a non-nil pointer as the target + // decode destination. If we try to pass in something that isn’t a non-nil pointer, then + // Decode() will return a form.InvalidDecoderError error. That error should be handled + // differently form a 400 error since it's a server side problem (ie 5xx error) + err = decodePostForm(r, formDecoder, &form) if err != nil { clientError(w, http.StatusBadRequest)