How To Make Http Url Form Encoded Request Golang

Alex Garella image

Alex Garella

27 April 2022

A POST request is typically sent via a HTML web form and there may be different content types which you can use to send such request. Let’s see the various types you can use when sending a POST request via HTML form

  • application/x-www-form-urlencoded: the keys and values are encoded in key-value tuples separated by '&', with a '=' between the key and the value. Non-alphanumeric characters in both keys and values are percent encoded (check out how to url encode a string in Go): this is the reason why this type is not suitable to use with binary data (use multipart/form-datainstead)
  • multipart/form-data: each value is sent as a block of data (“body part”), with a user agent-defined delimiter (“boundary”) separating each part. The keys are given in the Content-Disposition header of each part.
  • text/plain

In this article we are going to see how to send a POST request using a application/x-www-form-urlencoded content type using Golang.
Creating a url form encoded request in Golang is straightforward especially when using the methods that comes directly from Go’s standard library.

One of the key struct we are going to use for this is url,Values

Values maps a string key to a list of values. It is typically used for query parameters and form values. Unlike in the http.Header map, the keys in a Values map are case-sensitive.

This is a simple way we can wrap up different key-value pairs together when building a url formencoded POST request. This is particularly easy because the url package provides already an Encode method which we can use out of the box to percent encode our key-value pairs url.Values.Encode()

func (v Values) Encode() string

Encode encodes the values into “URL encoded” form (“bar=baz&foo=quux”) sorted by key.

URL form encoded request example

Now let’s see a concrete example on how we can send a url form encoded request in Go (Golang)

package main

import (
    "net/http"
    "net/url"
    "strconv"
    "strings"
    "log"
    "io/ioutil"
)

func main() {
    endpoint := "http://example.com/submit_form.php"
    data := url.Values{}
    data.Set("foo", "bar")
    data.Set("bar", "baz")

    client := &http.Client{}
    r, err := http.NewRequest("POST", endpoint, strings.NewReader(data.Encode())) // URL-encoded payload
    if err != nil {
        log.Fatal(err)
    }
    r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    r.Header.Add("Content-Length", strconv.Itoa(len(data.Encode())))

    res, err := client.Do(r)
    if err != nil {
        log.Fatal(err)
    }
    log.Println(res.Status)
    defer res.Body.Close()
    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        log.Fatal(err)
    }
    log.Println(string(body))
}