A request in HTTP is more than just an instruction to the server to respond with information for the resource uniquely identified by the request’s url. Aside the url, a request object has headers and optionally, a body among many other things.
The headers are key-value pairs of information exchanged between the client and the server in either directions of the HTTP request-response cycles. Both the client and the server are able to send meta-information packaged as key-value pair entries into headers. One of the most common headers in HTTP is the “Content-Type” header which indicates to the receiving end (can be either client or server) how to process or parse the request/response body. Enough has been said about headers but hey, that’s not our focus of today. Let’s talk about request body.
And, if you love my posts on Golang, then do well to subscribe to my Go Rapidly course on Youtube to get notified of the latest videos I post every other day.
HTTP Request Body
As indicated in the text above, HTTP requests can optionally send data to the server in many forms. JSON, Url Form Encoding, Raw Stream Of Bytes are the common encoding formats used to send request body data to backend servers. See my story on handling json request body in golang if that’s what you’re interested in. HTTP clients and servers largely depend on the “Content-Type” header to determine how to parse request/response body. Common values for the “Content-Type” header are application/json, application/atom+xml, application/pdf, application/octet-stream, application/x-www-form-urlencoded for stating that request/response body should be processed as JSON, XML, PDF, Raw Stream, or Form Data respectively. Modern RESTFul APIs favor JSON over XML encoding for both request body and response body because it is computationally easier to parse, and aesthetically easier for humans to read and understand JSON. However, in traditional monolithic web applications where data exchange between client and server isn’t done through APIs, HTML form is the goto technique for information exchange. To this effect, HTML forms are very important in modern web development and being able to parse request body encoded as application/x-www-form-urlencoded is a fundamental feature required of any self-respected web framework. One of the reasons why I love Golang is the fact that I can create complete web applications without relying on third-party libraries or frameworks. Frameworks are built to improve developer productivity by abstracting away mundane and repetitive tasks so that developers can focus on implementing core business solutions. As much as frameworks can boost your productivity, they can also get in your way so choose them wisely. Thank goodness, frameworks aren’t needed much in Golang. Have I talked too much? May be yes! but no worries, we’ll code soon. Stay with me!
URL Data Versus Form Encoded Body Data
Yes, you read this paragraph’s title right! Request data can be sent either through the url (usually known as query parameters) or the request body. We will discuss how to choose between the two before we end but believe me, 99.99% of forms in your web applications will be url-encoded and sent in the request body instead of the request url for obvious reasons. Data sent in the url is seen by users so sensitive information such as user account credentials, access tokens etc should not be sent in this manner. When in doubt, I suggest you choose url-encoded body.
Processing Request Data In Golang
Have you been waiting for this section? I bet you have! Ok, let’s get awesome!
Parsing both url and body request data in Golang is very easy but also very tricky if things aren’t done in the right order. Lemme give you the secret recipe here:
- Always set content type to application/x-www-form-urlencoded if-and-only-if you want to process request body as form-encoded data. This is very important. Adhere to it, thank me later. However, note that once your HTML form’s method is set to “POST” or “PUT”, this will be done for you automatically.
- Always invoke ParseForm or ParseMultipartForm on the request object in your handler before attempting to read url or body data from the request object. Note : call ParseMultipartForm if your form supports file upload else, ParseForm will do just fine.
According to the golang documentation on the net/http package, the following are true :
ParseForm populates r.Form and r.PostForm.
For all requests, ParseForm parses the raw query from the URL and updates r.Form.
For POST, PUT, and PATCH requests, it also parses the request body as a form and puts the results into both r.PostForm and r.Form. Request body parameters take precedence over URL query string values in r.Form.
For other HTTP methods, or when the Content-Type is not application/x-www-form-urlencoded, the request Body is not read, and r.PostForm is initialized to a non-nil, empty value.
If the request Body’s size has not already been limited by MaxBytesReader, the size is capped at 10MB.
ParseMultipartForm calls ParseForm automatically. ParseForm is idempotent.
When in doubt, always consult golang’s splendid documentation. This is also a reason why I’ll choose golang anytime.
Talk Is Cheap, Show Me The Code
Finally! Finally!! Finally!!! We’re here to get our hands dirty with code. In this sections, I will show you how to process request data sent in the url and also the body.
In the self-documenting snippet shown above, I iterate over the r.Form object to read data passed through both the url and request body. Note again that I invoked r.ParseForm() before attempting to read form values. The rationale is clearly spelt out in the net/http documentation here.
The shots below show how to hit the /signup url on the server with postman and the corresponding response logged on the server’s console.
Note from the postman screenshot above that pageindex=1 is appended to the url after the ?. This is how to pass data through the request url. Multiple query parameters are key-value pairs separated by &. Also note that though pageindex is a query parameter, it is also readable from the r.Form object, hence it’s printed in the console.
In the snippet below, I demonstrate how to read individual values from the r.Form object instead of looping through it as demonstrated above.
Most of my examples are simple because the focus is to help you understand the concepts. Once you’ve an understanding of how things work, you’re only limited by your imaginations and creativity. You can access the code from my github repo here.
Instead of just printing out the individual key-value pairs as demonstrated in my snippet, you’d rather assign them to fields in structs which will eventually be persisted to some database for permanent storage in a real application.
Also, though I used postman to test, this approach still works when you create HTML forms and assign appropriate names to input fields in the form.
Finally, if you love my posts on Golang, then do well to subscribe to my Go Rapidly course on Youtube to get notified of the latest videos I post every other day.
Thanks for reading!!!