Go form handling
Instead of passing a name
argument as a URL parameter as we did in our Hello World example, we can improve the user experience using HTML forms. The built-in http.Request
object gives us access to posted form variables, using the PostFormValue()
method.
We’ve removed the name
argument from the URL pattern, and have the GET
handler return the template without any context. In this case, the template will present the user with a <form>
.
An additional POST
handler accesses the name
form value and attaches an error
to the template context in case it’s missing.
package main
import (
"errors"
"html/template"
"net/http"
"strings"
"github.com/go-chi/chi"
)
var funcMap = template.FuncMap{
"Capitalize": strings.Title,
}
var tpl = template.Must(template.New("page").Funcs(funcMap).ParseFiles(
"templates/index.gohtml", "templates/greeting.gohtml"))
type tplData struct {
Greeting, Name string
Errors []error
}
func NewGreetingsRouter() *chi.Mux {
router := chi.NewRouter()
router.Get("/{greeting}", func(w http.ResponseWriter, r *http.Request) {
tpl.ExecuteTemplate(w, "index", nil)
})
router.Post("/{greeting}", func(w http.ResponseWriter, r *http.Request) {
var formErrors []error
name := r.PostFormValue("name")
if name == "" {
formErrors = append(formErrors, errors.New("missing required 'name' field"))
}
data := tplData{
Greeting: chi.URLParam(r, "greeting"),
Name: name,
Errors: formErrors,
}
tpl.ExecuteTemplate(w, "index", data)
})
return router
}
func main() {
router := chi.NewRouter()
router.Mount("/greeting", NewGreetingsRouter())
http.ListenAndServe("localhost:3000", router)
}
The logic for displaying the initial form, possible errors, or the final greeting, has been delegated to the template.
{{ define "greeting" }}
{{ if .Name }}
{{ if eq .Greeting "hello" }}
<p>Hello <strong>{{ .Name | Capitalize }}</strong>!</p>
{{ else }}
<p>Goodbye <strong>{{ .Name | Capitalize }}</strong>!</p>
{{ end }}
<a href="">try again</a>
{{ else }}
<p>Hey stranger, tell me your name:</p>
{{ if .Errors }}
<ul>
{{ range $err := .Errors }}
<li>{{ $err }}</li>
{{ end }}
</ul>
{{ end }}
<form method="post">
<label for="name">Male</label>
<input type="text" name="name" id="name" />
<input type="submit" value="submit" />
</form>
{{ end }}
{{ end }}