From 4e40ef8ed90ce217e4209256136929acc35935c7 Mon Sep 17 00:00:00 2001 From: tamsin johnson Date: Tue, 6 Feb 2024 16:46:46 -0800 Subject: [PATCH] lets-go:8.6 form parsing --- snippetbox/cmd/web/handlers.go | 24 +++++++----------------- snippetbox/cmd/web/helpers.go | 24 ++++++++++++++++++++++++ snippetbox/cmd/web/main.go | 5 +++++ snippetbox/go.mod | 1 + snippetbox/go.sum | 3 +++ 5 files changed, 40 insertions(+), 17 deletions(-) diff --git a/snippetbox/cmd/web/handlers.go b/snippetbox/cmd/web/handlers.go index 6e5176d..64fa536 100644 --- a/snippetbox/cmd/web/handlers.go +++ b/snippetbox/cmd/web/handlers.go @@ -63,32 +63,22 @@ func (app *application) snippetCreate(w http.ResponseWriter, r *http.Request) { } type snippetCreateForm struct { - Title string - Content string - Expires int - validator.Validator + Title string `form:"title"` + Content string `form:"content"` + Expires int `form:"expires"` + validator.Validator `form:"-"` } // snippetCreatePost ... func (app *application) snippetCreatePost(w http.ResponseWriter, r *http.Request) { - err := r.ParseForm() + var form snippetCreateForm + + err := app.decodePostForm(r, &form) if err != nil { app.clientError(w, http.StatusBadRequest) return } - expires, err := strconv.Atoi(r.PostForm.Get("expires")) - if err != nil { - app.clientError(w, http.StatusBadRequest) - return - } - - form := snippetCreateForm{ - Title: r.PostForm.Get("title"), - Content: r.PostForm.Get("content"), - Expires: expires, - } - form.CheckField(validator.NotBlank(form.Title), "title", "This field cannot be blank") form.CheckField(validator.MaxChars(form.Title, 100), "title", "This field cannot be more than 100 characters long") form.CheckField(validator.NotBlank(form.Content), "content", "This field cannot be blank") diff --git a/snippetbox/cmd/web/helpers.go b/snippetbox/cmd/web/helpers.go index 13a9866..6fb5e0c 100644 --- a/snippetbox/cmd/web/helpers.go +++ b/snippetbox/cmd/web/helpers.go @@ -2,11 +2,14 @@ package main import ( "bytes" + "errors" "fmt" "log/slog" "net/http" "runtime/debug" "time" + + "github.com/go-playground/form/v4" ) // newTemplateData ... @@ -56,3 +59,24 @@ func (app *application) clientError(w http.ResponseWriter, status int) { func (app *application) notFound(w http.ResponseWriter) { app.clientError(w, http.StatusNotFound) } + +// (app *application) ... +func (app *application) decodePostForm(r *http.Request, dst any) error { + err := r.ParseForm() + if err != nil { + return err + } + + err = app.formDecoder.Decode(dst, r.PostForm) + if err != nil { + var invalidDecoderError *form.InvalidDecoderError + + if errors.As(err, &invalidDecoderError) { + panic(err) + } + + return err + } + + return nil +} diff --git a/snippetbox/cmd/web/main.go b/snippetbox/cmd/web/main.go index 1a09036..bc5f130 100644 --- a/snippetbox/cmd/web/main.go +++ b/snippetbox/cmd/web/main.go @@ -11,6 +11,7 @@ import ( "snippetbox.chaosfem.tw/internal/models" + "github.com/go-playground/form/v4" _ "github.com/go-sql-driver/mysql" ) @@ -19,6 +20,7 @@ type application struct { logger *slog.Logger snippets *models.SnippetModel templateCache map[string]*template.Template + formDecoder *form.Decoder } // main it's the snippetbox webapp @@ -46,11 +48,14 @@ func main() { os.Exit(1) } + formDecoder := form.NewDecoder() + // setup the application app := &application{ logger: logger, snippets: &models.SnippetModel{DB: db}, templateCache: templateCache, + formDecoder: formDecoder, } logger.Info("starting server", slog.String("addr", *addr)) diff --git a/snippetbox/go.mod b/snippetbox/go.mod index d6e5a42..84b9d0d 100644 --- a/snippetbox/go.mod +++ b/snippetbox/go.mod @@ -3,6 +3,7 @@ module snippetbox.chaosfem.tw go 1.21.4 require ( + github.com/go-playground/form/v4 v4.2.1 // indirect github.com/go-sql-driver/mysql v1.7.1 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect github.com/justinas/alice v1.2.0 // indirect diff --git a/snippetbox/go.sum b/snippetbox/go.sum index 5138436..a9f8f45 100644 --- a/snippetbox/go.sum +++ b/snippetbox/go.sum @@ -1,3 +1,6 @@ +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/form/v4 v4.2.1 h1:HjdRDKO0fftVMU5epjPW2SOREcZ6/wLUzEobqUGJuPw= +github.com/go-playground/form/v4 v4.2.1/go.mod h1:q1a2BY+AQUUzhl6xA/6hBetay6dEIhMHjgvJiGo6K7U= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=