Validating form data
Right now there’s a glaring problem with our code: we’re not validating the (untrusted) user input from the form in any way. We should do this to ensure that the form data is present, of the correct type and meets any business rules that we have.
Specifically for this form we want to:
- Check that the
title
andcontent
fields are not empty. - Check that the
title
field is not more than 100 characters long. - Check that the
expires
value exactly matches one of our permitted values (1
,7
or365
days).
All of these checks are fairly straightforward to implement using some if
statements and various functions in Go’s strings
and unicode/utf8
packages.
Open up your handlers.go
file and update the snippetCreatePost
handler to include the appropriate validation rules like so:
package main import ( "errors" "fmt" "net/http" "strconv" "strings" // New import "unicode/utf8" // New import "snippetbox.alexedwards.net/internal/models" ) ... func (app *application) snippetCreatePost(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { app.clientError(w, http.StatusBadRequest) return } title := r.PostForm.Get("title") content := r.PostForm.Get("content") expires, err := strconv.Atoi(r.PostForm.Get("expires")) if err != nil { app.clientError(w, http.StatusBadRequest) return } // Initialize a map to hold any validation errors for the form fields. fieldErrors := make(map[string]string) // Check that the title value is not blank and is not more than 100 // characters long. If it fails either of those checks, add a message to the // errors map using the field name as the key. if strings.TrimSpace(title) == "" { fieldErrors["title"] = "This field cannot be blank" } else if utf8.RuneCountInString(title) > 100 { fieldErrors["title"] = "This field cannot be more than 100 characters long" } // Check that the Content value isn't blank. if strings.TrimSpace(content) == "" { fieldErrors["content"] = "This field cannot be blank" } // Check the expires value matches one of the permitted values (1, 7 or // 365). if expires != 1 && expires != 7 && expires != 365 { fieldErrors["expires"] = "This field must equal 1, 7 or 365" } // If there are any errors, dump them in a plain text HTTP response and // return from the handler. if len(fieldErrors) > 0 { fmt.Fprint(w, fieldErrors) return } id, err := app.snippets.Insert(title, content, expires) if err != nil { app.serverError(w, r, err) return } http.Redirect(w, r, fmt.Sprintf("/snippet/view/%d", id), http.StatusSeeOther) }
Alright, let’s give this a try! Restart the application and try submitting the form with a too-long snippet title and blank content field, a bit like this…

And you should see a dump of the appropriate validation failure messages, like so:
