Build Server With Go Under 10 minutes

Aniket Pal - Jan 23 '23 - - Dev Community

The introduction of microservice architecture revolutionised the way softwares are developed today. Post microservice architecture replaced monoliths, containers replaced virtual machines. With this transformations, almost every modern software is built in microservice architecture. Golang is widely used among developers building Microservices. Its usage can be seen across industries as a popular option for server-side application development.

Go Starter

Go is a great language for creating simple yet efficient web servers and web services. It provides a built-in HTTP package that contains utilities for quickly creating a web or file server.

Why Build backend Server with Go? ๐Ÿ—ฝ

The Story goes, Go was allegedly created by Google engineers while they waited for other programmes to compile. They had to completely rethink system development as a result of their displeasure with their toolset, which drove them to develop a lean, mean, and compiled solution that supports huge multithreading, concurrency, and performance under stress.

Every organisation looking at scale is leveraging Golang to build containerised microservices

Several programming languages have less memory and cannot communicate with the hardware. Thus, developers mostly prefer Golang that helps build software. Besides, it is the procedural language that is beneficial for implementing reliable, effective, and simple software. Golang supports the environment to accept different patterns that are equivalent to other more beneficial languages. Tech gaints have started using Go, post it's inception.

Companies using Golang

Graphics: Bacancy Techology

It can be a genuine delight to run Go on contemporary hardware, either inside containers or on virtual machines. Go was created to allow concurrency and scale as more cores are added since it was intended to run on multiple cores. If you are someone who is interested in the Cloud Native Ecosystem, Go is the language you should start with.

What we will build? ๐Ÿ‘จโ€๐Ÿš’

The following tutorial will include building a basic backend server with just main.go file. I won't be making the application complex by following the directory structure. Connecting DBs would make the tutorial a bit large and might confuse beginners who are just starting out with Go.

In the application we will learn how to add multiple routes, start server, write controllers and perform GET and POST requests.

System Design for Server

The schematic diagram above is an attempt to showcase how the server is to be designed to work. The server we will be building will have 2 routes one for GET and the other for POST. Where in the home route will be configured for GET and the form route for POST.

Pre-Requisite โš™๏ธ

If you don't have Go installed in your system follow the official docs to install it. Trust me it won't take more than 3 minutes to do it. To check if you have installed it properly, just run:

go version
Enter fullscreen mode Exit fullscreen mode

When I run the particular command, I get go version go1.17 darwin/amd64 in return. If you get something similar congratulations ๐ŸŽ‰ you are all set to begin your backend developer journey with Go.

Understanding: Syntax ๐Ÿ‘จโ€๐Ÿซ

Go is syntactically similar to C, but with memory safety, garbage collection, structural typing, and CSP-style concurrency. Now, if you have never coded in Golang before and don't have any clue how the syntax works. Refer to Namaste-Go. A learning repository, to get started with Go lang.

GitHub logo Aniket762 / namaste-go

A repository to learn the basics of Go Programming. The language was developed by Google Engineers but currently is widely used in the Cloud Native ecosystem. If you want to start your career in the landscape this is the starting point.

Namaste Go ๐Ÿ™

ProjectNamaste Golang (1)






Once, you are done with the basics let's dive into building the backend server with Go lang.

Developing the Backend ๐Ÿ‘จโ€๐Ÿ’ป

Let's create a directory goServer and change our current directory to it.

mkdir goServer && cd goServer
Enter fullscreen mode Exit fullscreen mode

Post running the command we are in the goServer directory, all you need to do now, create a main.go which you can name according to whatever naming convention you follow, say server.go. As mentioned before, we won't be following the modularised approach to keep things simple. So, let's create the file.

touch main.go
Enter fullscreen mode Exit fullscreen mode

Running the command, creates an empty file in our working directory over here which is goServer.

We need to define a package for the Go file. Since this will be the main file we have, we add the package main.

package main
Enter fullscreen mode Exit fullscreen mode

The above line is the first line of the program.

Importing Packages ๐Ÿ›๏ธ

Now, let's import all the necessary packages we require to build our application.

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

    "github.com/gorilla/mux"
)
Enter fullscreen mode Exit fullscreen mode

Now, let us understand why did we include so many packages into our application. Demystifying the packages:

1๏ธโƒฃ fmt: for printing message
2๏ธโƒฃ log: for logging errors
3๏ธโƒฃ net/http: for handling HTTP requesting when creating GO APIs
4๏ธโƒฃ gorilla/mux: for URL matcher and routing. It helps in implementing request routers and match each incoming request with its matching handler.

If, I would have been you and read all the imports, I would have been pretty much confused. But, trust me once you read the blog I can bet you would get a clear idea why we included the following packages.

Creating the go.mod file which will store all the necessary packages required, it is similar to package.json.

go mod init github.com/Aniket762/namaste-go/goServer
Enter fullscreen mode Exit fullscreen mode

To ensure that the go.mod file matches the source code in the module, we run

go mod tidy
Enter fullscreen mode Exit fullscreen mode

All the imported packages except for one is already present with the binary file you executed while installing Go. So, let's install Gorilla Mux.

go get "github.com/gorilla/mux"
Enter fullscreen mode Exit fullscreen mode

If you are a JavaScript developer, the following command is pretty much similar to npm install <package_name>

Lastly, before we run the program to check if everything is in sync till now. We add the main() function which would get first executed when we compile the program.

func main() {
    fmt.Printf("Hello from GoServer ๐Ÿ‘‹")
}
Enter fullscreen mode Exit fullscreen mode

Summarising the entire codebase till now,

package main

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


    "github.com/gorilla/mux"
)

func main(){
    fmt.Printf("Hello from GoServer ๐Ÿ‘‹")
}
Enter fullscreen mode Exit fullscreen mode

To run the following Go Script execute the following command.

go run main.go
Enter fullscreen mode Exit fullscreen mode

If you get Hello from GoServer ๐Ÿ‘‹ in the console. Wohoo! You are all set to proceed further!

Building the server ๐Ÿ’ช

First creating a new request router. The router is the main router for our web application and will later be passed as parameter to the server. It will receive all HTTP connections and pass it on to the request handlers we will register on it. We create the router, in the main function.

r := mux.NewRouter()
Enter fullscreen mode Exit fullscreen mode

Post registering the router, let's define the endpoints using HandleFunction. We call HandleFunction by r.HandleFunc(...)

   r.HandleFunc("/",greetingsHandler).Methods("GET")
   r.HandleFunc("/form",formHandler).Methods("POST")
Enter fullscreen mode Exit fullscreen mode

In HandleFunc we provide 2 parameters, firstly the route in which we want to see the magic and secondly we write the name of the particular controller function which performs the magic. The corresponding GET and POST has the regular meaning, to build the CRUD operation for the application just add PUT and DELETE according to the route.

Writing the GET Route

Now, as we have defined the routes, let us write the controllers. Starting out with the greetingsHandler aka GET Controller.

func greetingsHandler(w http.ResponseWriter, r *http.Request){
    fmt.Fprintf(w,"Greeting from Go Server ๐Ÿ‘‹")
}
Enter fullscreen mode Exit fullscreen mode

By default, this function accepts a ResponseWriter to send a response back and a Request object that sends the parameters to the server. The controller simply sends back a message.

To check if our GET function is working, let's write the code to spin up the server in the main function.

        fmt.Printf("Starting server at port 8000\n")
    log.Fatal(http.ListenAndServe(":8000",r))
Enter fullscreen mode Exit fullscreen mode

The Listen and Serve function keep the custom port open, here 8000. Until and unless the program is interrupted the server is up.

Before we move forward with the POST request handler let us, check if everything is functioning as expected. Let's comment out the POST route and go for it. Your code should look something like this ๐Ÿ‘‡

package main

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

    "github.com/gorilla/mux"
)

func greetingsHandler(w http.ResponseWriter,r *http.Request){
    fmt.Fprintf(w,"Greeting from Go Server ๐Ÿ‘‹")
}


func main(){
    r := mux.NewRouter()

    r.HandleFunc("/",greetingsHandler).Methods("GET")

    fmt.Println("Hello from GoServer ๐Ÿ‘‹")
    fmt.Printf("Starting server at port 8000\n")
    log.Fatal(http.ListenAndServe(":8000",r))
}
Enter fullscreen mode Exit fullscreen mode

Running the server ๐Ÿƒโ€โ™‚๏ธ

Now, we have the basic server ready. Let us create a build and then run it.

Using the particular command we generate the .exe file if we are on windows and .deb if in linux. Ultimately generating a binary file which can be executed.

go build
Enter fullscreen mode Exit fullscreen mode

Post creating the binary file, we execute the file via the following command.

go run main.go
Enter fullscreen mode Exit fullscreen mode

Hit, localhost:8000 in your favourite browser. If it is something like this as shown below. Cheer yourself up, you have completed 80% of the tutorial.

Get Request UI

Leveling Up: Post Request ๐Ÿš€

It's great to see you are still reading. The beauty of Go can be enjoyed when you start with Post Requests. We will be using json encoding so, let's import another module for it,

import(
   "encoding/json"
)
Enter fullscreen mode Exit fullscreen mode

First let's create a simple struct Founder, which will consists name, age, email address and name of the company they have founded.

type Founder struct{
    Name string `json:"name"`
    Age uint32 `json:"age"`
    Email string `json:"email"`
    Company string `json:"company"`
}
Enter fullscreen mode Exit fullscreen mode

If you are a JavaScript developer struct is similar to ES6 class. Now, let us define a slice, which is similar to vectors in C++.

var founders []Founder
Enter fullscreen mode Exit fullscreen mode

A slice is similar to an array, the difference is that when you want to use arrays in Golang you need to define the length. This is why we use a slice, we also tell it that it will contain posts. Over here founders is a slice of type Founder.

Let us insert dummy data into our slice, such that when we return our slice after perform POST request we can visualise more than element in our slice.

founders = append(founders, Founder{Name:"Mehul",Age:23,Email:"random@random.com",Company: "BharatX"})
Enter fullscreen mode Exit fullscreen mode

Let us write the script for POST Request Handler aka form Handler one step at a time.

func formHandler(w http.ResponseWriter, r *http.Request){
     w.Header().Set("Content-Type","application/json")
}
Enter fullscreen mode Exit fullscreen mode

We define the the Header for the particular controller over here. Weโ€™re just setting the header โ€œContent-Typeโ€ to โ€œapplication/jsonโ€.

func formHandler(w http.ResponseWriter, r *http.Request){
    w.Header().Set("Content-Type","application/json")

    var founder Founder
    json.NewDecoder(r.Body).Decode(&founder)
}
Enter fullscreen mode Exit fullscreen mode

We send parameters while sending the request, as key value pairs. The request object is broken down into string with decoder method. Let's try to play a bit around with the parameter we have received.

func formHandler(w http.ResponseWriter, r *http.Request){
    w.Header().Set("Content-Type","application/json")

    var founder Founder
    json.NewDecoder(r.Body).Decode(&founder)

    founder.Age = founder.Age * 2;
    founders = append(founders,founder)

    json.NewEncoder(w).Encode(founders)
}
Enter fullscreen mode Exit fullscreen mode

We multiple the age of the founder by two, and append it to the slice. Then we use the encoding package to encode all the founders data as well as returning it at the same line. Ultimately, sending in the POST request, modifying the data, appending into the slice and then returning back the slice.

So, your final piece of code should look like:

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"

    "github.com/gorilla/mux"
)

type Founder struct{
    Name string `json:"title"`
    Age uint32 `json:"age"`
    Email string `json:"email"`
    Company string `json:"company"`
}

var founders []Founder

func greetingsHandler(w http.ResponseWriter,r *http.Request){
    fmt.Fprintf(w,"Greeting from Go Server ๐Ÿ‘‹")
}

func formHandler(w http.ResponseWriter, r *http.Request){
    w.Header().Set("Content-Type","application/json")

    var founder Founder
    json.NewDecoder(r.Body).Decode(&founder)

    founder.Age = founder.Age * 2;
    founders = append(founders,founder)

    json.NewEncoder(w).Encode(founders)
}

func main(){
    r := mux.NewRouter()

    founders = append(founders, Founder{Name:"Mehul",Age:23,Email:"random@random.com",Company: "BharatX"})

    r.HandleFunc("/",greetingsHandler).Methods("GET")
    r.HandleFunc("/form",formHandler).Methods("POST")

    fmt.Println("Hello from GoServer ๐Ÿ‘‹")
    fmt.Print("Starting server at port 8000\n")
    log.Fatal(http.ListenAndServe(":8000",r))
}
Enter fullscreen mode Exit fullscreen mode

The process does not end here, let us check on what we have developed so far is working or not. Firstly, let's build and spin up the server

go build && go run main.go
Enter fullscreen mode Exit fullscreen mode

API testing with Postman ๐Ÿ“ฌ

Now, let's head over to Postman. You can use anything you want to but I prefer Postman.
Postman setup for API testing
Firstly, put the API endpoint in this case it is, http://localhost:8000/form, select POST from the dropdown. Navigate to Body tab and choose raw and then select JSON. Write dummy data, here is the one I wrote:

{
    "name":"Kunal Shah",
    "age":42,
    "email":"kunal@coolguy.com",
    "company":"CRED"
}
Enter fullscreen mode Exit fullscreen mode

Hit the Send button. Check for the status code and the output which you got. Incase it's exactly what you were expecting, then it's time for celebration ๐Ÿป๐Ÿฅณ

Outro ๐Ÿ’š

Firstly, thanks a lot if you are still reading. Remember, Go is like chess or, well, the game of Go: it takes a moment to learn and a lifetime to master. Luckily, unlike chess, Goโ€™s difficulty goes down with experience and soon youโ€™ll be coding fast and furious programs in one of the worldโ€™s most modern languages.

The purpose of this blog was to give programmers who are enthusiastic about backend development with Golang a kickstart. The server built consists of basic features such as multiple routes, creation of GET and POST request, building binaries, running server and ultimately giving a basic understanding on how exactly Go works.

I plan to write more backend development with Go tutorials. If you don't want to miss out, follow me at Twitter. Till then checkout the wonderfully curated Go Documentation. Incase, you have some questions regarding the article or want to discuss something under the sun feel free to connect with me on LinkedIn ๐Ÿ’–

If you run an organisation and want me to write or create video tutorials please do connect with me ๐Ÿค

. . . . . . . . . . . . . .