How Form Submissions Are Represented In HTTP
Created on April 6, 2025
Updated on April 7, 2025
networking/http
When you look at what arrives at the server over the wire (HTTP is just plain text, no special wire-format) in HTTP form submissions, it looks something like this:
POST /admin/login HTTP/1.1
Host: localhost:8873
Connection: keep-alive
Content-Length: 41
Content-Type: application/x-www-form-urlencoded
Origin: http://localhost:8873
[... a bunch of additional headers]
email=david%40gmail.com&password=abc
You notice that it’s a string (or []byte
) after the headers where each special character is url-encoded and each field is divided by an &
.
How to work with form submissions in Go
In Golang, you call err := r.ParseForm()
which iterates the form submission and parses it into a map (r.PostForm
). Once that’s done, you can access the form data with r.PostForm.Get("email")
.
In the HTML, you need to define the name="name"
property in each form field, see for instance this login form (notice the <input>
tags):
<h3>Login:</h3>
<form action="/admin/login" method="post">
<fieldset>
<label>email:
<input type="email" name="email">
</label>
<label>password:
<input type="password" name="password">
</label>
</fieldset>
<button type="submit">
Login
</button>
</form>
And here is a snippet how you can work with it in Go:
func (app *application) adminLoginPost(w http.ResponseWriter, r *http.Request) {
type userLoginForm struct {
email string
password string
}
// Here, you call r.ParseForm()
// This will take the data from the POST request
// (email=david%40gmail.com&password=pa55word)
// and make it available in r.PostForm as a map. (see below)
err := r.ParseForm()
if err != nil {
log.Printf("Failed parsing form: %v", err)
http.Redirect(w, r, "/admin/login", http.StatusSeeOther)
return
}
// Here, email and password are available from r.PostForm:
form := userLoginForm{
email: r.PostForm.Get("email"),
password: r.PostForm.Get("password"),
}
...
}