Let’s Go, Everything you need to know about creating a RESTful Api in Go — Part I

Supun Muthutantrige
5 min readApr 14, 2019

--

Detailed overview on go internal server

PART I

In this section we will create a simple endpoint to accept a http request.

First let’s create a simple go file and describe what each section does.

[app.go]package mainimport (
"fmt"
"log"
"net/http"
)
func main() {
http.HandleFunc("/", homePageHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func homePageHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("Request came through to Home Page")
}

In previous article, I mentioned about the package structure, executable and package archive etc (Link: Go Packages). Now lets take each section and see how go works behind the scene to accept http requests and serve.

import (
"fmt"
"log"
"net/http"
)

In the import section, there are three packages we have used. “fmt” (formatted I/O) is similar to C’s printf and scanf. According to the documentation this is much simpler compared to C’s printf and scanf (Link: source). “log” is a simple logging library and there are some out of the box methods you can use to get the job done.

net/http” is the most important of the three for the purpose of handling http requests.

HTTP Refresher

Before we dive into the package, let’s look at some network fundamentals.

HTTP (Hyper Text Transfer Protocol) is a protocol that two machines over the internet (client and server) uses to communicate with each other. Think of it as grammar which shapes the language in use to communicate. TCP (Transmission Control Protocol) is used to transmit data between two machines. It establishes the connection and guarantees the delivery from one machine to another. HTTP uses TCP to communicate over the internet.

Let’s try to simplify using an analogy

Think that I have written a letter (HTML), in a way both parties can understand (HTTP) and I have a trustworthy postman (TCP) to deliver my letter. Next, I need to have a way to specify the recipient, so the postman knows whom to deliver my letter to. This sender and recipient identification is done via something knows as IP (Internet Protocol). With an IP address in place, I can say to my postman, “Go to this house (machine/server) in this address (IP) and hand it over to this person (port)”. Once the letter is safely delivered, the postman comes back and let me know that the recipient accepted it (Acknowledgement), so I can be sure that the intended party received it.

With the above high level understanding, let’s look at how clients and servers communicate via the network.

A Socket is nothing but the combination of an IP address and a Port. So for the communication to work between a client and a server, there should be a client socket, a network connection and a server socket. A server socket should contain a well defined port number to it, so all the clients connect to the server know where exactly it should connect to (in our analogy, whom exactly to deliver our letter to) since the server is accepting requests 24/7. On the other hand, client sockets could have randomly assigned port numbers since it is short lived and required only when communicating with the server.

In order for HTTP to work, first the server should open a socket connection (server has an IP address and a dedicated port to receive client requests) and listen to any incoming requests. The client, on the other hand, initiates a connection request (client too has an IP address and gets a random port number) and sends a request to the server socket. Upon receiving the request, the server assigns the client request to a process, to a thread in a thread queue or to an event in an event loop depending on the underlying server architecture and the main socket goes back to accept incoming requests. In the client request itself, is a footprint of the client socket address, hence the serve knows where to send the response to once the server side processing is completed. Once the server sends the HTTP response back to the client, the connection will be closed.

The above explanation shows how a simple server works behind the scene. With this knowledge at hand, let’s look at how internal go server works under the hood.

Go net/http package

net

“Package net provides a portable interface for network I/O, including TCP/IP, UDP, domain name resolution, and Unix domain sockets.

Although the package provides access to low-level networking primitives, most clients will need only the basic interface provided by the Dial, Listen, and Accept functions and the associated Conn and Listener interfaces.” — source

http

“Package http provides HTTP client and server implementations.” — source

http.ListenAndServe

func ListenAndServe(addr string, handler Handler) error

http.ListenAndServe(“:8080”, nil) starts a server listening to port 8080 and the second argument of this method is a handler. Since we have passed nil as the handler, go uses DefaultServeMux as the default handler.

We have a server up and running and listening to incoming requests on port 8080. Now we should define an endpoint so that the clients can query various resources from the server.

http.HandleFunc

func HandleFunc(pattern string, handler func(ResponseWriter, *Request))

http.HandleFunc(“/home”, homePageHandler) expects a resource in uri path “/home” which executes handler function “homePageHandler”. This way if a client sends a request to /home, func homePageHandler will get executed.

func homePageHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("Request came through to Home Page")
}

This way http.HandleFunc maps certain endpoints to dedicated handlers.

http.ResponseWriter

http.ResponseWriter

As seen above, a handler takes two arguments and the first one is the http.ResponseWriter. The ResponseWriter is an interface which is used by the handler to construct an HTTP response.

func homePageHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.WriteHeader(http.StatusOK)
}

http.Request

*http.Request

As the name implies, http.Request is a struct which is the expected request by the server or the request sent by the client.

So to sums up, ListenAndServe starts the go server listening to incoming requests on a specified port, where each endpoint is assigned to a handler function which takes a request struct and a response interface, which then process the request and prepare the response and sends the info back to the client.

Now let’s run the application and see what we get. First go to the go source file location and execute the following,

go run app.go

This will start the serve and will be listening to port 8080. Now go the the browser and type http://localhost:8080/. You can see logs been printed in the server console, which indicates that the server is accepting requests. Browser on the other hand will be empty since the server is not sending any payload back to the client. In the next section will see how we can enhance this to be a proper REST endpoint.

check my personal blog to view more — icodeforpizza

checkout my latest video content blogging series for golang — youtube

Prev Section — Go Packages

Next Section — Part II

--

--