Golang net.http handling request/responses
Tags: go, http, tcp, webdev
Published: 2020-05-26 18:14:01

<h4>Introduction</h4>

In this post, I want to go over what I've learnt in studying how to create a web server that listens on a TCP network that handles client-server request/responses.  Here I will discuss Golang's <i>Handler</i> from the <i>net.http</i> package and how it is used to achieve this.

<h4>What is an Interface?</h4>

An interface is a type that defines functionality

<h4>What is a <i>Handler</i>?</h4>

In order to process requests and responses on a network we need a <i>Handler</i>.

A <i>Handler</i> is an interface and anything that implements <i>ServeHTTP</i> is implicity a <i>Handler</i> as well.

Take a look at the following from the <i>http.Handler</i> interface:
<pre>
<code>
type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}
</code>
</pre>

<p>Here we have a function <i>ServeHTTP</i> that takes in a <i>ResponseWriter</i> and a pointer to a <i>Request</i>.</p>

<ul>
<li>
<i>Request</i> is a pointer to a struct that contains all the data needed to process the request.
</li>
<li>
<i>ResponseWriter</i> allows us to set headers and send response text back to the client.
</li>
</ul>

<p>
<b>Bottom line:</b> A <i>Handler</i> is type that has a <i>ServeHTTP</i> function that takes in a <i>ResponseWriter</i> and a pointer to a <i>Request</i>.
</p>

<p>As mentioned before, anything that implements <i>ServeHTTP</i> would be a <i>Handler</i> as well.  This allows for polymorphism where different types can be passed in anywhere a <i>Handler</i> is required.  In particular, the <i>http.ListenAndServe</i> function that listens and serves incoming requests is an example of this.</p>


<h4>How to Use a <i>Handler</a>?</h4>

The <i>ListenAndServe</i> function requires an address string and a <i>Handler</i>:

<pre><code>
http.ListenAndServe

func ListenAndServe(addr string, handler Handler) error
</code></pre>

To paraphrase the Golang documentation, the <i>ListenAndServe</i> function listens on the TCP network address <i>addr</i> and makes a call to Serve with <i>handler</i> to handle requests on incoming connections.

Generally the handler is <code>nil</code>, and the <i>DefaultServeMux</i> is used:

<pre>
<code>
http.ListenAndServe(":8080", nil)
</code>
</pre>

The following tells the <i>ListenAndServe</i> function to listen on port 8080 using the <i>DefaultServeMux</i>.

A mux in laymen's terms is a data multiplexer that provides routing for incoming and outgoing traffic.  It is responsible for deciding where the data should go and what to do with it.  The mux is essentially responsible for URL routing and processing GET and POST requests.  More to be talked about in a future post.

Although not a common practice, you can also pass in a custom handler as long as the type implements a <i>Handler</i>.  But most of the times, the <i>DefaultServeMux</i> is usually sufficient.

<h4>How to Process a Request?</h4>

The second argument of a <i>Handler</i> is a <i>Request</i>.  A <i>Request</i> is a struct with many fields such as Method, URL, Form, PostForm, and etc.  It is here where we can extract request data and determine which functions to call to process the request.

When working with a POST request, <i>Request</i> has fields that allow for accessing form data:
<ul>
<li>
<i>Form</i> gets data from both the URL query string and form data
</li>
<li>
<i>PostForm</i> gets data from form data only
</li>
<li>
<i>FormValue</i> is a helper function to get the value from a given name
</li>
</ul>

The <i>Form</i> and <i>PostForm</i> fields are only available after <i>ParseFrom</i> is called.

<i>http.ParseForm</i> is a function that has a pointer reference to a <i>Request</i>

Example on how to call <i>ParseForm</i>:
<pre>
<code>
func (m myHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
  err := req.ParseForm()
  if err != nil {
    log.Println(err)
  }
}
</code>
</pre>

After calling <i>ParseForm</i>, accessing the <i>Form</i> or <i>PostForm</i> will return <i>url.Values</i>.  <i>url.Values</i> is a map that takes a string and returns a slice of strings.  The returned value will be a series of key-value pairs from the form data being sent.

<h4>How to Send Back a Response?</h4>

The <i>ResponseWriter</i> will be used to send responses back to the client.  A
<i>ResponseWriter</i> is an interface that has a <i>Header</i>.  Use the <i>Header</i> to set values for the response such as <code>Content-Type</code> and etc.

<code>res.Header().Set("Content-Type", "text/html; charset=utf-8")</code>

From there, you can then finish off processing the response by passing in the <i>ResponseWriter</i> to another function that will write and send back to the client.  If templates are being used, the code can look like this:

<code>tpl.ExecuteTemplate(res, "mypage.gohtml", data)</code>

The following are other types of responses that can be done:

HTML

<pre>
<code>
res.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprintln(res, "Put html code in here")
</code>
</pre>

Text

<pre>
<code>
res.Header().Set("Content-Type", "text/plain; charset=utf-8")
fmt.Fprintln(res, "This is some text")
</code>
</pre>

JSON

<pre>
<code>
res.Header().Set("Content-Type", "text/json; charset=utf-8")
fmt.Fprintln(res, "{\"item\": \"value\"}")
</code>
</pre>

Additionally you may need to use <code>json.Marshal(data)</code> from the <i>json</i> package when dealing with large data sets rather than hard-coding like the above example.

This post is still in the works and will continually get updated.  Hit me up with any comments and feedback.  Peace.