Go: The Server Language

0
3018

Go, also known as Golang, is an open source programming language that makes it easy to build simple, reliable and efficient software. It is a highly performant, smoothly compiled, portable, modular, object-oriented, statically typed, and garbage collected language.

Have you ever been confused about which programming language to choose while starting a new project? I must confess that I faced the situation recently. My bare minimum requirement was to create simple yet efficient Web servers which could be developed and started within minutes. I considered many languages including Java, JS, C++ and C, but in the end I decided to go with a language that was new to me — the Go language, also known as Golang.

The next obvious question is, “Why Go?” The answer is simple: The compilation time and verbosity of Go projects is much less when compared to other languages. Since it is a statically typed language, most of the errors are immediately caught at compilation time. It also has inbuilt concurrency support, which makes its code safe to run in a multi-threaded environment. The concept of Go routine (a lightweight process), channels and select statements help users in implementing concurrent programs and utilise the multi-core system to its maximum.

From the point of view of adaptability and supportability, Go is pretty popular as it is backed and developed by Google engineers Ken Thomson (previously developed C, UNIX, UTF-8), Rob Pike (previously developed UNIX, UTF-8), Robert Griesemer (previously developed JVM, HotSpot) and is widely used in many big companies like YouTube, Apple, Dropbox, GitHub, Intel, and so on. Developed in 2007, it is more than a decade old now. In 2009, it was launched as an open source programming language.

In this article, we will be developing a Web server that can accept a GET request and serve a response. The Web server is a program running on a computer with static/dynamic IP and a specified port, and it listens to an HTTP request sent by the client. The browser (client) sends the data to a server in the form of packets over a network, to which the server may respond with some requested data.

Figure 1: Code

To develop an HTTP server all we need is a Go compiler and a text/code editor. The Golang compiler can be downloaded from the Go official binary distribution, which is available at https://golang.org/dl/ for FreeBSD (release 10-STABLE and above), Linux, MacOS (10.11 and above), and Windows operating systems for both 32-bit (386) and 64-bit (amd64) x86 processor architectures.

Once downloaded, the complete processes for installation and testing the installation can be found at https://golang.org/doc/install#install. If the project involves dependencies on other Go projects, modules need to be used as required by the default dependency management system from Go 1.13 onwards.

The Go modules are collections of Go packages stored in a file tree with the go.mod file at its root. The go.mod file contains entries that are also the import path used for the root directory and its dependency requirements.

Figure 2: Browser

Up next, for writing the code, we need a text editor like textpad, notepad or any IDE. I will be using VSCODE, a free and open source code editor that can be downloaded from https://code.visualstudio.com/download.

To support networking, Golang has a package named ‘net’, which contains the http package used to create the HTTP/ HTTPS server and make client requests. The net package (https://golang.org/src/net/net.go) provides an interface to support network I/O like TCP/IP, UDP, domain name resolution, and emails. The http package has a ListenAndServe method, which starts the server and listens to the incoming requests.

This method accepts two arguments:

  1. address: This is the combination of the IP address and the port of the machine in a string format. If only the port is provided, such as ‘:9000’, then this port is accessible by all the IP addresses of the system.
  2. handler: This argument is of the type Handler interface. This uses the serveHTTP method, which is internally called whenever the ListenAndServe method is executed.
  3. The serveHTTP method is of format ServeHTTP (res http.ResponseWriter, req *http.Request), and is the main function that accepts the request and returns the response.

Before moving forward let us see the code for a server running on port 9000, which replies with a text ‘Welcome to the World of Go Lang’ when opened in a browser:

package main

import (
“net/http”
))

// HttpHandler is a handler struct
type HttpHandler struct{}

// implement `ServeHTTP` method on `HttpHandler` struct
func (h HttpHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
// create response binary data
data := []byte(“Welcome to the world of Go Lang”)
// write `data` to response
res.Write(data)
}
func main() {
// create a new handler
handler := HttpHandler{}
// listen and serve on localhost
http.ListenAndServe(“:9000”, handler)
}

As you can see above, I wrote a Go program in a file named http-server.go, wherein I created an HttpHandler and implemented the serveHTTP method.

When this program is run by executing the command go run http-server.go in the console, the main function is executed, which calls the http ListenAndServe method, thereby starting the server on the address provided as an argument. Inside serveHTTP, I created binary data, which is written to the response using the write method.

Upon hitting the address http://localhost:9000 in the browser, the data sent by the server is displayed as a response. The server continuously runs until it is forcefully stopped by typing CTRL in the server console.

The above code creates a simple server, but the problem with it is that it responds to all the requests with the same response. For example, if the URL contains /index.html or /test.pdf, the response is always constant.

Figure 3: Mux

To solve this, we need a ServerMux, a route based control mechanism which handles different responses for different URLs. ServerMux is a built-in structure present in the HTTP package, and it accepts a function for a route. When the requests match the path, the corresponding function is called to render the desired response.

For instance, /api/accounts maps to the accounts function, which in turn returns account related information, whereas /api/subscription maps to the subscription function which returns subscription information.

The code below depicts different outputs for the URLs /home, /home/accounts, /home/subscription:

package main

import (
“fmt”
“net/http”
))

func main() {
// Create a new ServerMux
mux := http.NewServeMux()

// handle `/` route
mux.HandleFunc(“/home”, func(res http.ResponseWriter, req *http.Request) {
fmt.Fprint(res, “ Welcome to Home Page!”)
})

// handle `Accounts` route
mux.HandleFunc(“/home/accounts”, func(res http.ResponseWriter, req *http.Request) {
fmt.Fprint(res, “ Welcome to Accounts page!”)
})

mux.HandleFunc(“/home/subscription”, func(res http.ResponseWriter, req *http.Request) {
fmt.Fprint(res, “ Welcome to Subscription Page!”)
})

// Listen and serve using ServerMux
http.ListenAndServe(“:9000”, mux)

}

This article has covered the basics of setting a server in Go language. For further details, one can go through the documents at https://golang.org/.

In order to learn Golang one can visit https://tour.golang.org/welcome/1 and work on a hands-on session at https://play.golang.org/.

LEAVE A REPLY

Please enter your comment!
Please enter your name here