Go migrate from-express
Tags: go, beginners, gin
Published: 2022-10-30 17:31:05

## Background: why the switch?

NodeJS made backend programming simpler for programmers as it enables you to write services in JavaScript. While NodeJS is still relevant today, JavaScript as a programming language isn’t ideal to write. Microsoft helped the JavaScript community with the introduction of TypeScript but that didn’t solve the underlying problem: the code is still transpiled to JavaScript.

I can write an entire article on JavaScript and TypeScript. Drop a comment if you’d like me to do that. Moving on…

## Source code

You can find all the code from this article here: [GitHub](https://github.com/saranshabd/migrate-from-express)

I highly suggest that you go through the code to better understand things. Use this article just for understanding the reasoning behind the decisions made in the repository.

## Picking the right framework

The focus will be to write an HTTP server. [ExpressJS](https://expressjs.com/) is the most popular framework to build HTTP servers using JavaScript. The base assumption from here will be that you are already familiar with it, and are now trying to switch to Go. I am not going to focus on Go itself. The focus will be how to replicate the same ExpressJS structure in Go. Some familiarity with Go will be helpful.

[Gin](https://gin-gonic.com/) is one of the most popular frameworks in Golang to build HTTP servers. My general advice would be to go for the most popular framework and libraries when picking a language you’re not comfortable with yet. Once you have mastered the default configurations and setup then you can focus on optimization and picking the right framework for your use case.

## Basic project setup and directory structure

A good project structure is always going to help you down the road as the project scales. Code management is dependent on the programming language itself. Here are a few must-read articles on Golang project structure standard conventions:
1. Standard Package Layout: [https://www.gobeyond.dev/standard-package-layout](https://www.gobeyond.dev/standard-package-layout/)
2. Golang standards - project layout: [https://github.com/golang-standards/project-layout](https://github.com/golang-standards/project-layout)

### Standard practices to structure Go code

Note that it is not a standard practice to put all the code inside the `src` directory in Go. The following directories are a must in almost all the projects:

#### `cmd`

This is the application's entrypoint. It’s the Go equivalent of `index.js` in JavaScript projects. You don’t want to put a lot of code here; just project-level structs/interfaces and basic initialization setup.

The `cmd` directory must not include any implementation logic. Note that the root directory is not allowed to have any external dependencies. It must only call/initiate the respective application packages.

#### `pkg`

This is where you define the public packages in your application. This is where you write the actual implementation logic. **Packages inside the `pkg` directory are meant to be shared outside of your application**; keep that in mind.

#### `internal`

This directory is similar to the `pkg` directory except it is only meant to be used by your application. This layout pattern is enforced by the Go compiler itself.

The `internal` directory may also have a `pkg` sub-directory to better segregate the code. The `pkg` sub-directory will contain packages that are shared amongst the `internal` packages.

#### `vendor`

This directory contains your application dependencies. It is an automatically managed directory so you don’t have to manually change anything here. All you need to do is execute `go mod vendor` to create and maintain this directory. The base assumption here is that you are using Go modules for managing dependencies.

Note that you will need to add `-mod=vendor` to the `go build` command for building the project.

#### `configs`

Your application configurations will go here. You are probably going to read most of the configurations from the environment variables. You may use this directory to extract configurations from the environment variables and store them in a struct.

### Project structure example

```bash
cmd/
	__app_name__/
		init.go # entrypoint
pkg/
	__app_name__/
		users/
		auth/
internal/
	__app_name__/
		razorpay/
vendor/
	github.com/
	golang.org/
	google.golang.org/
configs/
	configs.go
build/
	deploy/
		Dockerfile
go.mod
go.sum
```

## Route structure and middleware

The `main.go` file inside the `cmd/__app_name__` directory will be simple. Its sole purpose will be to initiate the project and setup things in order.

```go
package main

import (
	"fmt"
	"github.com/saranshabd/migrate-from-express/cmd/mfe/http"
	"os"

	"github.com/gin-gonic/gin"
	"github.com/saranshabd/migrate-from-express/cmd/mfe/logger"
	"github.com/saranshabd/migrate-from-express/configs"
)

func main() {

	// Create a Gin server application with default configurations & middlewares
	app := gin.Default()

	// Load all the application HTTP endpoints
	http.InitRoutes(app)

	// Start listening to HTTP requests from the client
	logger.App.Info().Msgf("Firing it up on %d port number.", configs.Configs.Port)
	if err := app.Run(fmt.Sprintf(":%d", configs.Configs.Port)); err != nil {
		logger.App.Error().Err(err).Msg("Could not fire up Gin :/")
		os.Exit(1) // Kill the application
	}
}
```

All the route handlers will go inside the `internal/__app_name__/` directory, based on the directory structure discussed above.

```bash
internal/
	middlewares/
	__route_name__/
		routes.go
		handler1.go
		handler2.go
```

Firstly, we must ensure that all the HTTP responses we send are by default JSON. We can create a simple middleware for this purpose.

```go
package middlewares

import "github.com/gin-gonic/gin"

func JSONResponse() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Writer.Header().Set("Content-Type", "application/json")
		c.Next()
	}
}
```

Secondly, we need a place to import all the HTTP route handlers and map them to specific endpoints. We can place this piece of code inside the `cmd` directory since all we will do is important a bunch of handlers and map them to their respective endpoints.

```go
package http

import (
	"github.com/gin-gonic/gin"
	"github.com/saranshabd/migrate-from-express/internal/mfe/middlewares"
)

func InitRoutes(app *gin.Engine) {
	// Ensure that all the HTTP responses are by-default in the JSON format
	app.Use(middlewares.JSONResponse())

	// Load all the application HTTP routes
	// ...
}
```

That’s it! The router and middleware setup in Gin is similar to that in ExpressJS. We can call this `InitRoutes` function from the `main.go` file.

## Extract request parameters from different sources

We can move on to creating a bunch of HTTP endpoints with the current project setup. The endpoints will primarily focus on extracting request parameters from different sources e.g. request body, query and URI. The request params will all be returned in the response object as is.

> I have created a bunch of simple HTTP utility functions for better code readability. These functions don’t have anything to do with the tutorial so I won’t go into the detail. You can find all the source code on GitHub.

Go treats functions as first-class citizens so your HTTP setup is going to be just a bunch of functions. An HTTP handler in Gin takes a single argument: Gin context. Context is one of the fundamentals of Go. If you’re not already familiar with it then I’d suggest you take some time in understanding them before you continue.

### Extract from request body

Go provides a beautiful “binding” package out of the box for basic validation. The binding module can be loosely compared with “Joi” package in NodeJS. The primary difference between the two is that binding is part of Go language itself so we don’t have to define our validation logic separately.

This is how a typical Go HTTP handler looks like:

```go
type CreateExtractParamsArgs struct {
	Arg1 string `json:"arg1" binding:"required"`
	Arg2 int64  `json:"arg2" binding:"required"`
	Arg3 bool   `json:"arg3,omitempty"` // optional
}

func CreateExtractParams(c *gin.Context) {
	// Extract the parameters from the request.body & validate the object received
	var args CreateExtractParamsArgs
	if err := c.BindJSON(&args); err != nil {
		// Return HTTP 400 if invalid params are passed
		http.InvalidRequestParams(c)
		return
	}

	// Return the params object in response if everything is fine
	http.RespondOkay(c, "Request parameters extracted successfully", args)
}
```

Note that I am using the custom `http` package, which is just a utility package I created. You can refer to the `RespondOkay` function below:

```go
func RespondOkay(c *gin.Context, message string, data any) {
	Respond(c, http.StatusOK, true, message, data)
}

func Respond(c *gin.Context, statusCode int, success bool, message string, data any) {
	c.JSON(statusCode, &gin.H{
		"success": success,
		"message": message,
		"data":    data,
	})
}
```

The `omitempty` property will remove the field while deserialising, to let’s say JSON. The struct value of the field will be the default value of the type. E.g. if you access `args.Arg3` then you will receive `false` in the response. **Beware of this behaviour. This is not JavaScript!**

## Extract from query parameters

We can use the same pattern to validate query parameters using the binding package. We will use the `BindQuery` function instead of `BindJSON`. Everything else will look the same.

```go
type GetExtractParamsArgs struct {
	Arg1 string `form:"arg1" json:"arg1" binding:"required"`
	Arg2 int64  `form:"arg2" json:"arg2" binding:"required"`
	Arg3 bool   `form:"arg3" json:"arg3,omitempty"` // optional
}

func GetExtractParams(c *gin.Context) {
	// Extract the parameters from the request.query & validate the object received
	var args GetExtractParamsArgs
	if err := c.BindQuery(&args); err != nil {
		// Return HTTP 400 if invalid params are passed
		http.InvalidRequestParams(c)
		return
	}

	// Return the params object in response if everything if fine
	http.RespondOkay(c, "Request parameres extracted successfully", args)
}
```

### Extract from the URI

Again, we can just extend the binding package to validate path parameters i.e. `/path/:arg/`. You define the path parameters in Gin like this:

```go
r.GET("/:specificPath/", GetSpecificExtractParams)
```

We can swap the `BindQuery` function with `BindUri` and keep everything the same. By now, you must be getting the hang of Go.

```go
type GetSpecificExtractParamsArgs struct {
	SpecificPath string `uri:"specificPath" json:"specificPath" binding:"required"`
}

func GetSpecificExtractParams(c *gin.Context) {
	// Extract the parameters from the request.params & validate the object received
	var args GetSpecificExtractParamsArgs
	if err := c.BindUri(&args); err != nil {
		// Return HTTP 400 if invalid params are passed
		http.InvalidRequestParams(c)
		return
	}

	// Return the params object in response if everything is fine
	http.RespondOkay(c, "Request parameters extracted successfully", args)
}
```

## Header-based authorization

Authentication and authorization are the base of almost all the REST APIs out there. Auth is usually built on top of HTTP headers. We can use the binding package to validate headers received in the request and write middlewares to add custom logic on top of that.

Here’s a simple example of a auth header to check the source of the incoming request:

```go
type VerifiedSourcesArgs struct {
	VerifiedSource string `header:"verified-source" binding:"required"`
}

const (
	AcceptedSource = "accepted-source"
)

func IsVerifiedSource() gin.HandlerFunc {
	return func(c *gin.Context) {
		// Extract the header value from the HTTP request
		var args VerifiedSourcesArgs
		if err := c.ShouldBindHeader(&args); err != nil {
			http.InvalidHeaders(c)
			return
		}

		// Check if the source of the incoming request is accepted
		if args.VerifiedSource != AcceptedSource {
			http.InvalidHeaders(c)
			return
		}

		// Continue with the chain of middlewares/handlers
		c.Next()
	}
}
```

### The `Next` function in Gin middlewares

Gin middlewares look awfully similar to ExpressJS middlewares. But, there is a nasty distinction between the two; the `Next` function. **You do not need to necessarily call the `Next` function in a Gin middleware.**

This is an important distinction because you cannot expect a request to terminate just because you returned from the middleware without calling the `Next` function. The next in-chain function will still be called when your middleware terminates… unless you abort the request.

```go
func AbortAndRespond(c *gin.Context, statusCode int, message string, data any) {
	c.AbortWithStatusJSON(statusCode, &gin.H{
		"success": false,
		"message": message,
		"data":    data,
	})
}
```

Instead of calling `c.JSON` we need to call `c.AbortWithStatusJSON` function to set the status code and JSON response before aborting the request. This is a nasty distinction especially for programmers coming from the NodeJS background. Beware!

---

That's it! We setup HTTP routes, validated incoming request data from different sources, and created auth middlewares for the application.

This is just the beginning. The application didn't interact with a database or a third-party service; both are fundamentals to most of the services. That's for the next article in the series :)

Drop a comment if there's anything I missed or could've explained better.

Cheers! 👋