Welcome To Golang By Example

Menu
  • Home
  • Blog
  • Contact Us
  • Support this website
Menu

HTTP server or Parse incoming application/x-www-form-urlencoded request body in Go (Golang)

Posted on December 31, 2020January 1, 2021 by admin

Note: This post is parsing the application/x-www-form-urlencoded request at the server end. If you using an HTTP client and trying to send the application/x-www-form-urlencoded request then please see the below link

https://vikasboss.github.io/http-client-urlencoded-body-go/

Table of Contents

  • Overview
  • Example

Overview

The applcation/x-www-form-urlencoded content-type request body is like a giant query string. Similar to the query string in a URI it is a key-value pair having the below format

key1=value1&key2=value21&key2=value22&key3=value3

where there are below key-value pairs

  • key1, value1
  • key2 has two values i.e value21 and value22.
  • key3, value3

Each key-value pair is separated by & in case of multiple values for the same key there will be two entries of that key-value pair. Also, each key and value is URLencoded similar to the query string.

Now the question that might be coming to the mind is if x-www-form-urlencoded is just like query string then why does it exist. The reason is that the query string is part of the URI and since there is a limit on the length of the URI, you can send a limited number of key-value pairs in the query string.  While there is no limit for the length of the x-www-form-urlencoded request body. However, it is limited by the max request body size allowed by the server which is generally 10MB for most of the servers. Now let’s see how we can parse the x-www-form-urlencoded in golang

Example

Request object of net/http package has two fields which can hold the form-data. https://golang.org/src/net/http/request.go

The two fields are

  • Form – It holds combine data of query string and x-www-form-urlencoded request body
  • PostForm– It holds only x-www-form-urlencoded request body

To get the x-www-form-urlencoded request body we need to first call the below function on the request object

request.ParseForm()

This function essentially does below things

  • It parses the query string present in the URL and populates the Form field of the request object
request.Form
  • After that, if the request method is PUT, POST, or PATCH  and the request body content-type is x-www-form-urlencoded, then it also parses the request body and populates the above two fields of the request object
request.Form
request.PostForm
  • request.PostForm will be initialized to a non-nil, empty value if the request body content-type is not x-www-form-urlencoded or the request method is not PUT, POST, or PATCH
  • The body parameters will take precedence over URL query string values i.e if there is a key that is present in both form body and in query param. Then the value in the form body will take precedence
  • Also, note that this function is idempotent.

Both Form and PostForm field are of the below type

type Values map[string][]string

It is a map where

  • The key is a string
  • The value is an array of strings. It is an array of strings because there can be multiple values

So essentially to get the x-www-url-encoded request body we need to call the ParseForm function first on the request object. This will populate both the Form and PostForm field. Then we can access these fields to get the x-www-form-urlencoded body. For example, let’s say we have the below x-www-form-urlencoded body.

name=John
age=21
hobbies=sports
hobbies=music

Then you can access the name field like below

request.Form["name"]
request.PostForm["name"]

both will return

["John"]

It is an array because the key can have multiple values.

Also, the request’s object defines one more function FormValue which can be used to get the first value associated with the key. It just returns the first value and not the array. For example

request.FormValue("hobbies")

will return

sports

Let’s see a program for that as well

package main

import (
	"fmt"
	"net/http"
)

type employee struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	createEmployeeHanlder := http.HandlerFunc(createEmployee)
	http.Handle("/employee", createEmployeeHanlder)
	http.ListenAndServe(":8080", nil)
}

func createEmployee(w http.ResponseWriter, r *http.Request) {
	headerContentTtype := r.Header.Get("Content-Type")
	if headerContentTtype != "application/x-www-form-urlencoded" {
		w.WriteHeader(http.StatusUnsupportedMediaType)
		return
	}
	r.ParseForm()
	fmt.Println("request.Form::")
	for key, value := range r.Form {
		fmt.Printf("Key:%s, Value:%s\n", key, value)
	}
	fmt.Println("\nrequest.PostForm::")
	for key, value := range r.PostForm {
		fmt.Printf("Key:%s, Value:%s\n", key, value)
	}

	fmt.Printf("\nName field in Form:%s\n", r.Form["name"])
	fmt.Printf("\nName field in PostForm:%s\n", r.PostForm["name"])
	fmt.Printf("\nHobbies field in FormValue:%s\n", r.FormValue("hobbies"))

	w.WriteHeader(200)
	return
}

In the above program, we are running a server on port 8080. Also notice that we are first calling the ParseForm function and then accessing the Form and PostForm fields of the request object.

Also, see how we are accessing the value of the name field in Form as well as PostForm

r.Form["name"]
r.PostForm["name"]

Also, we are calling the FormValue function on the request object to access the hobbies field as below

r.FormValue("hobbies")

Run the above program. It will start a server at port 8080

Now let’s try some curl calls.

  • Passing only the x-www-form-urlencoded body. No query string.
curl -v -X POST 'http://localhost:8080/employee' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'name=John' \
--data-urlencode 'age=18' \
--data-urlencode 'hobbies=sports' \
--data-urlencode 'hobbies=music'

Output

request.Form:: 
Key:name, Value:[John] 
Key:age, Value:[18] 
Key:hobbies, Value:[sports music] 

request.PostForm:: 
Key:name, Value:[John] 
Key:age, Value:[18] 
Key:hobbies, Value:[sports music] 

Name field in Form:[John] 

Name field in PostForm:[John] 

Hobbies field in FormValue:sports
  • Passing the x-www-form-urlencoded body. Passing an extra field gender in the query string. Notice in the output that the gender field is not present in PostForm but present in Form
curl -v -X POST 'http://localhost:8080/employee?gender=male' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'name=John' \
--data-urlencode 'age=18' \
--data-urlencode 'hobbies=sports' \
--data-urlencode 'hobbies=music'

Output

request.Form:: 
Key:age, Value:[18] 
Key:hobbies, Value:[sports music] 
Key:gender, Value:[male] 
Key:name, Value:[John] 

request.PostForm:: 
Key:name, Value:[John] 
Key:age, Value:[18] 
Key:hobbies, Value:[sports music] 

Name field in Form:[John] 

Name field in PostForm:[John] 

Hobbies field in FormValue:sports
  • Passing the x-www-form-urlencoded body. Also passing the same key ie age in the query string. age=20 is passed in the query string and age=18 is passed in the post body.  The value 20 for age will not be present in the PostForm field but present in the Form field. Since body parameters take precedence therefore age=18 is the first value in the array in the Form field. If you run r.FormValue(“age”) then it will return 18 and not 20
curl -v -X POST 'http://localhost:8080/employee?age=20' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'name=John' \
--data-urlencode 'age=18' \
--data-urlencode 'hobbies=sports' \
--data-urlencode 'hobbies=music'

Output

request.Form:: 
Key:hobbies, Value:[sports music] 
Key:name, Value:[John] 
Key:age, Value:[18 20] 

request.PostForm:: 
Key:name, Value:[John] 
Key:age, Value:[18] 
Key:hobbies, Value:[sports music] 

Name field in Form:[John] 

Name field in PostForm:[John] 

Hobbies field in FormValue:sports
  • go
  • golang
  • Follow @golangbyexample

    Popular Articles

    Golang Comprehensive Tutorial Series

    All Design Patterns in Go (Golang)

    Slice in golang

    Variables in Go (Golang) – Complete Guide

    OOP: Inheritance in GOLANG complete guide

    Using Context Package in GO (Golang) – Complete Guide

    All data types in Golang with examples

    Understanding time and date in Go (Golang) – Complete Guide

    ©2025 Welcome To Golang By Example | Design: Newspaperly WordPress Theme