Skip to content

Parsing form data from requests in Go

Published: at 08:23 PM

We will learn how to process and use the form data when it’s submitted to a route in your Go web server. The net/http standard package will be used to handle both our routes and the form data. No libraries or frameworks are required.

If you don’t already, learn how to create a simple web server in go.

How do our form look like?

To get started, you can find an example form with a go web server at the repository here, branch for beginning of article. Here is a picture reference for the form:

Form

We are collecting information for an event. The form has fields for the full name, event date, event type, details, and interest. The form is submitted to the /create route via a POST method <form action="/create" method="POST">.

HTML form elements have the name attribute you can (and should) use to reference the fields for form data when the form is submitted to the server. For example, our form example have: <input name="fullName" />, <select name="eventType"> e.t.c .

Names of form fields

Before, we get started, here is a snippet of our handler function for the /create route:

func createEvent(resWriter http.ResponseWriter, request *http.Request) {
	resWriter.Write([]byte("Create event called"))
}

Get values from form data

To parse a form data, we need to take two significant steps:

  1. Parse the request body.
  2. Retrieve the values from the parsed form data.

1. Parse the request body

To parse the request body, we need to call a method on the request struct, ParseForm().

Now, we will update our handler function to parse the form data:

func createEvent(resWriter http.ResponseWriter, request *http.Request) {
    err := request.ParseForm()
    if err != nil {
        http.Error(resWriter, "Error parsing form data", http.StatusBadRequest)
        return
    }
    resWriter.Write([]byte("Create event called"))
}

2. Retrieve the values from the parsed form data

After parsing the form data, we can now retrieve the values from the request.PostForm map.

The PostForm map contains the form values with the form field names as keys and the form field values as slices of strings.

To retrieve a specific form field value, you can use the request.PostForm.Get(fieldName) method. For example, to retrieve the value of the fullName field, you can use request.PostForm.Get("fullName"). If there is no matching field name in the form, this method will return an empty string "". This way, we can get the value for each form field values.

However, it works a bit different for fields like checkboxes. Fields that can have multiple values. Because the request.PostForm map actually is a map with a string as key and slices of string as values, this means a key can contain more than one value.

request.PostForm: map[string][]string

The Get method on the PostForm request.PostForm.Get(fieldName) gets only the first value in the string slice for the field and if the field is not present returns an empty string. For fields with a single value like fullName (input text), request.PostForm[fullName] is actually a string slice with one value. For fields like checkboxes, it can contain multiple strings.

Hence, to retrieve the values for checkboxes, we use r.PostForm["checkboxFieldName"].

Now, let’s update our handler function to retrieve form values:

// let's create a struct type for our form values
type NewEventRequest struct {
	fullName string
	eventDate string
	eventType string
	details string
	interest []string
}

func createEvent(resWriter http.ResponseWriter, request *http.Request) {
    err := request.ParseForm()
    if err != nil {
        http.Error(resWriter, "Error parsing form data", http.StatusBadRequest)
        return
    }

	newEventRequest := NewEventRequest{
		fullName: request.PostForm.Get("fullName"),
		eventDate: request.PostForm.Get("eventDate"),
		eventType: request.PostForm.Get("eventType"),
		details: request.PostForm.Get("details"),
		interest: request.PostForm["interest"],
	}

    resWriter.Header().Set("Content-Type", "application/json")
	resWriter.WriteHeader(http.StatusCreated)
	resWriter.Write([]byte(newEventRequest.fullName + " event has been created"))
}

Expecting other form value types aside from string

The r.PostForm.Get() method always returns the form data as a string. Whenever you are expecting a field value to be a number, and want to represent it in your Go code as an integer, you need to manually convert the form data to an integer using strconv.Atoi(), and send a 400 Bad Request response if the conversion fails.

Here’s an example of how to use strconv.Atoi():

durationStr := request.PostForm.Get("duration")
duration, err := strconv.Atoi(durationStr)
if err != nil {
    http.Error(resWriter, "Invalid duration value", http.StatusBadRequest)
    return
}

The request.Form map

There is an alternative way to access form values besides using request.PostForm. This method is request.Form.

The request.Form map includes the form data from any request body as well as any query string parameters. Therefore, if our form was submitted to /create?orgId=mandem, we could retrieve the value of the orgId parameter by calling request.Form.Get("orgId").

Keep in mind that if there is a conflict (if a key exists in both form data and query params), the value from the request body will take precedence over the query string parameter.

request body >>> query params

Utilizing the request.Form map can be beneficial if your application transmits data both in an HTML form and through the URL, or if your application does not differentiate between how parameters are passed.

The request.PostForm is populated for only POST, PATCH and PUT requests. Meanwhile, irrespective of their HTTP method, the request.Form is populated for all requests.

Conclusion

In this article, we learned how to parse and retrieve form values from requests in Go. We learned how to parse the request body and retrieve the form values from the parsed form data. We also learned how to handle different types of form fields and how to handle form values that are not strings.

We also learned about the request.Form map and how it can be used to access form values and query string parameters.

Branch for complete code: here

Happy coding!