lets-go:8.6 form parsing

This commit is contained in:
tamsin johnson 2024-02-06 16:46:46 -08:00
parent 1541305022
commit 4e40ef8ed9
5 changed files with 40 additions and 17 deletions

View File

@ -63,32 +63,22 @@ func (app *application) snippetCreate(w http.ResponseWriter, r *http.Request) {
} }
type snippetCreateForm struct { type snippetCreateForm struct {
Title string Title string `form:"title"`
Content string Content string `form:"content"`
Expires int Expires int `form:"expires"`
validator.Validator validator.Validator `form:"-"`
} }
// snippetCreatePost ... // snippetCreatePost ...
func (app *application) snippetCreatePost(w http.ResponseWriter, r *http.Request) { func (app *application) snippetCreatePost(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm() var form snippetCreateForm
err := app.decodePostForm(r, &form)
if err != nil { if err != nil {
app.clientError(w, http.StatusBadRequest) app.clientError(w, http.StatusBadRequest)
return 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.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.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") form.CheckField(validator.NotBlank(form.Content), "content", "This field cannot be blank")

View File

@ -2,11 +2,14 @@ package main
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"net/http" "net/http"
"runtime/debug" "runtime/debug"
"time" "time"
"github.com/go-playground/form/v4"
) )
// newTemplateData ... // newTemplateData ...
@ -56,3 +59,24 @@ func (app *application) clientError(w http.ResponseWriter, status int) {
func (app *application) notFound(w http.ResponseWriter) { func (app *application) notFound(w http.ResponseWriter) {
app.clientError(w, http.StatusNotFound) 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
}

View File

@ -11,6 +11,7 @@ import (
"snippetbox.chaosfem.tw/internal/models" "snippetbox.chaosfem.tw/internal/models"
"github.com/go-playground/form/v4"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
) )
@ -19,6 +20,7 @@ type application struct {
logger *slog.Logger logger *slog.Logger
snippets *models.SnippetModel snippets *models.SnippetModel
templateCache map[string]*template.Template templateCache map[string]*template.Template
formDecoder *form.Decoder
} }
// main it's the snippetbox webapp // main it's the snippetbox webapp
@ -46,11 +48,14 @@ func main() {
os.Exit(1) os.Exit(1)
} }
formDecoder := form.NewDecoder()
// setup the application // setup the application
app := &application{ app := &application{
logger: logger, logger: logger,
snippets: &models.SnippetModel{DB: db}, snippets: &models.SnippetModel{DB: db},
templateCache: templateCache, templateCache: templateCache,
formDecoder: formDecoder,
} }
logger.Info("starting server", slog.String("addr", *addr)) logger.Info("starting server", slog.String("addr", *addr))

View File

@ -3,6 +3,7 @@ module snippetbox.chaosfem.tw
go 1.21.4 go 1.21.4
require ( require (
github.com/go-playground/form/v4 v4.2.1 // indirect
github.com/go-sql-driver/mysql v1.7.1 // indirect github.com/go-sql-driver/mysql v1.7.1 // indirect
github.com/julienschmidt/httprouter v1.3.0 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect
github.com/justinas/alice v1.2.0 // indirect github.com/justinas/alice v1.2.0 // indirect

View File

@ -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 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=