Working with URL encoded form values

In the book, we discussed how to send and received multipart form data. That is, forms containing both text fields and file uploads, typically using the content type as multipart/form-data. When we are working with only text fields, it is sufficient to instead use the content type, application/x-www-form-urlencoded and send the data as a URL encoded set of key value pairs. For example, as described by the MDN article, say=Hi&to=Rheo will be the request payload for a form with two text fields, say and to with the values, Hi and Rheo respectively.

In this blog post, we will write a client and a server to send and process form data.

Let’s get started!

Prerequisites

Reading URL encoded form data in a Go server

Reading URL encoded form data in a server’s handler function involves two key steps:

  1. Call ParseForm() method of the request object
  2. Then, retrieve the values of the fields using FormValue()

Example code snippet:

func handleForm(w http.ResponseWriter, req *http.Request) {
	// this will look for application/x-www-form-urlencoded
	// content type
	err := req.ParseForm()
	if err != nil {
		// if there was an error here, we return the error
		// as response along with a 400 http response code
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// once the form has been parsed correctly
	// we can obtain the form fields  using
	// req.FormValue passing the field name as the key
	// see ./post-method.html for the field names

	// it's worth noting here that FormValue() will return
	// the first value if there are multiple values specified
	// in the request
	// if you want to access the multiple values specified,
	// use req.Form directly (see https://pkg.go.dev/net/http#Request)
	say := req.FormValue("say")
	to := req.FormValue("to")

    // do something with the values read
    ..
}

You can find the complete code for the form handler in form_handler.go.

To run the application:

go build
./go-form-url-encoded.md # or .\go-form-url-encoded.exe 

Using a browser as the client

First, let’s make a request to the server from a browser by visiting http://localhost:8000.

Here is a video demonstration of using the application from a browser.

Key points to note from the above video are:

  1. The “raw” request data (payload) is: say=Hi&to=Rheo
  2. The content-type header is set as, Content-Type: application/x-www-form-urlencoded

Both are automatically done for us when we click on the “Send my greetings” button.

Sending URL encoded form data from a Go client

Now, let’s say you want to write a test for the handleForm() handler function. You will need to send the relevant data as URL encoded form fields. Here is a code snippet showing you how:

func TestHandleForm(t *testing.T) {
	w := httptest.NewRecorder()

    // set the key value pairs
	formBody := url.Values{
		"say": []string{"hi"}, // we only have a single element, but these need to be a slice
		"to":  []string{"rheo"}, // same as above
	}
	dataReader := formBody.Encode() // this perform the URL encoding and returns us a string

	req := httptest.NewRequest(
		http.MethodPost,
		"http://localhost",
		strings.NewReader(dataReader), // we need a io.Reader
	)

    // set the content-type header
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	handleForm(w, req)

    // rest of the test
}

You can find the complete code for the form handler test function in form_handler_test.go.

Outside of test functions, you can use the same approach with http.NewRequest or http.NewRequestWithContext.

Key references:

Learn more