Top 10 Framework Golang Library to Build Microservice

Kecci
7 min readJan 30, 2021

--

In this day, a lot of open source library golang to support build application. I should recommend for you some library that could help to initiate project with simple design, clean code, and have good performance.

1. CLI commands (spf13/cobra)

Do you want to build some CLI commands?

Cobra is both a library for creating powerful modern CLI applications as well as a program to generate applications and command files.

I use this library to manage command app to execute runner the app, initialize config, and start the Rest API.

Cobra-based application organizational structure:

├── app
│ ├── main.go
│ ├── cmd
│ └── root.go

in app/main.go :

package mainimport (
"app/cmd"
)
func main() {
cmd.Execute()
}

in app/cmd/root.go :

package cmdvar rootCmd = &cobra.Command{
Use: "hugo",
Short: "Hugo is a very fast static site generator",
Long: `A Fast and Flexible Static Site Generator built with love by spf13 and friends in Go. Complete documentation is available at http://hugo.spf13.com`,
Run: func(cmd *cobra.Command, args []string) {
// Do Stuff Here
},
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}

Cobra: https://github.com/spf13/cobra

2. Configuration Reader (spf13/viper)

Viper is a complete configuration solution for Go applications.

Viper can reading from:

  • JSON,
  • TOML,
  • YAML,
  • HCL,
  • INI,
  • envfile, and
  • Java properties config files

example config/config.toml :

address="localhost"
port="9090"

Reading config.go :

func ReadConfig() {
viper.SetConfigName("config/config.toml")
viper.SetConfigType("toml")
err := viper.ReadInConfig()
if err != nil {
panic(fmt.Errorf("Fatal error config file: %s \n", err))
}
}

Use value from config in main.go :

func main() {
address := viper.Get("address")
port := viper.Get("port")
fmt.Printf("address: %s", address)
fmt.Printf("port: %s", port)
}

Viper: https://github.com/spf13/viper

3. Web framework (labstack/echo)

High performance, minimalist Go web framework

Installation

// go get github.com/labstack/echo/{version}
go get github.com/labstack/echo/v4

Example

package main

import (
"net/http"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)

func main() {
// Echo instance
e := echo.New()

// Middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())

// Routes
e.GET("/", hello)

// Start server
e.Logger.Fatal(e.Start(":1323"))
}

// Handler
func hello(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
}

4. Dependency Injection (uber-go/fx)

I found this library is very useful and you no need to generate anything. Just code. Very modular and clear layer.

A dependency injection based application framework for Go.

func main() {
fx.New(injectModule()).Run()
}

func injectModule() fx.Option {
return fx.Options(
fx.Provide(
NewTimeOutContext,
NewDbConn,
),
repository.Module,
service.Module,
outbound.Module,
server.Module,
controller.Module,
)
}

Uber-go/fx: https://github.com/uber-go/fx

5. Swagger Generator, UI, and Validation

In swagger section, I must use diffrent 3 libraries, because I could not found any library that can contains 3 them in 1 library. If you have recommend please comment for me below.

a. Swagger generator (swaggo/swag)

Swag converts Go annotations to Swagger Documentation 2.0.

We’ve created a variety of plugins for popular Go web frameworks. This allows you to quickly integrate with an existing Go project (using Swagger UI).

Supported Web Frameworks:

  • gin
  • echo
  • buffalo
  • net/http

Swag has handled your swagger docs. So you no longer need to write swagger.yml or swagger.json. What you need to do is just write annotations. This is an example:

// @title Blueprint Swagger API
// @version 1.0
// @description Swagger API for Golang Project Blueprint.
// @termsOfService http://swagger.io/terms/
// @contact.name API Support
// @contact.email martin7.heinz@gmail.com
// @license.name MIT
// @license.url https://github.com/MartinHeinz/go-project-blueprint/blob/master/LICENSE
// @BasePath /api/v1
func main() {
...
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
...
}

swaggo/swag: https://github.com/swaggo/swag

b. Swagger UI (swaggo/echo-swagger)

Because I’m using echo, so I choose this to user interface for swagger.

Example of use:

package mainimport (
"github.com/labstack/echo/v4"
"github.com/swaggo/echo-swagger"
_ "github.com/swaggo/echo-swagger/example/docs" // docs is generated by Swag CLI, you have to import it.
)
// @title Swagger Example API
// @version 1.0
// @description This is a sample server Petstore server.
// @termsOfService http://swagger.io/terms/
// @contact.name API Support
// @contact.url http://www.swagger.io/support
// @contact.email support@swagger.io
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host petstore.swagger.io
// @BasePath /v2
func main() {
e := echo.New()
e.GET("/swagger/*", echoSwagger.WrapHandler) e.Logger.Fatal(e.Start(":1323"))
}

swaggo/echo-swagger: https://github.com/swaggo/echo-swagger

c. Swagger validation (go-swagger/go-swagger)

This package contains a golang implementation of Swagger 2.0 (aka OpenAPI 2.0): it knows how to serialize and deserialize swagger specifications.

Installation:

go get github.com/go-swagger/go-swagger/cmd/swagger

Run this to validate:

swagger validate api/docs/swagger.yaml

Output:

2021/01/30 22:47:01 
The swagger spec at "api/docs/swagger.yaml" is valid against swagger specification 2.0

go-swagger/go-swagger: https://github.com/go-swagger/go-swagger

6. Custom Logger (sirupsen/logrus)

Logrus is a structured logger for Go (golang), completely API compatible with the standard library logger.

Example:

package main

import (
log "github.com/sirupsen/logrus"
)

func main() {
log.WithFields(log.Fields{
"animal": "walrus",
}).Info("A walrus appears")
}

sirupsen/logrus: https://github.com/sirupsen/logrus

7. Mock Generator (vektra/mockery)

A mock code autogenerator for Golang

Installation:

go get github.com/vektra/mockery/v2/.../

Generate mock:

./bin/mockery --all

Output:

vektra/mockery: https://github.com/vektra/mockery

8. Migrate (golang-migrate/migrate)

Database migrations written in Go. Use as CLI or import as library.

Database drivers run migrations:

Installation:

$ go get -u -d github.com/golang-migrate/migrate/cmd/migrate

Command create migration file :

migrate create -ext sql -dir database/migrations -seq create_user

Command run up migration :

migrate -database "mysql://user:pass@tcp(localhost:3600)/user" -path=database/migrations up

Command run down migration :

migrate -database "mysql://user:pass@tcp(localhost:3600)/user" -path=database/migrations down

golang-migrate/migrate: https://github.com/golang-migrate/migrate

9. Messaging (NSQ)

NSQ Topology

NSQ Component

  1. nsqlookupd (daemon manage topologies / routes)
  2. nsqd (daemon manage receives, queues, and delivers messages)
  3. nsqadmin (default Web UI of nsq)

example docker-compose: (nsqlookupd, nsqd, nsqadmin)

version: '3'services:nsqlookupd:image: nsqio/nsqcommand: /nsqlookupdports:- "4160:4160"- "4161:4161"nsqd:image: nsqio/nsqcommand: /nsqd --lookupd-tcp-address=nsqlookupd:4160depends_on:- nsqlookupdports:- "4150:4150"- "4151:4151"nsqadmin:image: nsqio/nsqcommand: /nsqadmin --lookupd-http-address=nsqlookupd:4161depends_on:- nsqlookupdports:- "4171:4171"

Execute:

To run docker:
$ docker-compose up -d
or if use name (docker-compose-nsq.yml):
$ docker-compose -f docker-compose-nsq.yml up -d
To check container docker:
$ docker-compose ps
To see logs:
$ docker-compose logs
To check nsq web ui: (assuming port is 32770)
$ curl http://127.0.0.1:32770/ping

In golang:

Create Folder:├── consume
│ └── consume.go
└── publish
└── publish.go

consume.go :

package mainimport ("log""sync""github.com/nsqio/go-nsq")func main() {wg := &sync.WaitGroup{}wg.Add(1)decodeConfig := nsq.NewConfig()c, err := nsq.NewConsumer("My_NSQ_Topic", "My_NSQ_Channel", decodeConfig)if err != nil {log.Panic("Could not create consumer")}c.AddHandler(nsq.HandlerFunc(func(message *nsq.Message) error {log.Println("NSQ message received:")log.Println(string(message.Body))return nil}))err = c.ConnectToNSQD("127.0.0.1:4150")if err != nil {log.Panic("Could not connect")}log.Println("Awaiting messages from NSQ topic \"My NSQ Topic\"...")wg.Wait()}

Run consume.go :

$ go run consume/consume.go

publish.go :

package mainimport ("log""github.com/nsqio/go-nsq")func main() {config := nsq.NewConfig()p, err := nsq.NewProducer("127.0.0.1:4150", config)if err != nil {log.Panic(err)}err = p.Publish("My_NSQ_Topic", []byte("sample NSQ message"))if err != nil {log.Panic(err)}}

Run publish :

$ go run publish/publish.go

nsqio/go-nsq: https://github.com/nsqio/go-nsq

10. SQL (jmoiron/sqlx)

sqlx is a library which provides a set of extensions on go’s standard database/sql library.

What I love in sqlx is they can struct scan ! Quick and simple use.

Example of StructScan :

    place := Place{}
rows, err := db.Queryx("SELECT * FROM place")
for rows.Next() {
err := rows.StructScan(&place)
if err != nil {
log.Fatalln(err)
}
fmt.Printf("%#v\n", place)
}

jmoiron/sqlx: https://github.com/jmoiron/sqlx

Additional

Go routine grouping (sync/errgroup)

Fluent SQL generation for golang (Masterminds/squirrel)

Golang Linter (golangci/golangci-lint)

Circuit Breaker (gojek/heimdall)

Go tool generate tags (fatih/gomodifytags)

Conclusion

To build application, we should to know what features that we have, especially if we want to build continues application and collaboration between team. I suggest to have a solid and readable code, so it can more maintainable until become legacy (maybe 5–10 years later).

3 keys of build application:

  1. Simple Design (Project structure & dependencies)
  2. Clean Code (Readable & maintainable)
  3. Modular (Solid & flexible skeleton)

To wrap all these libraries, I have a template or skeleton project with simple design and clean code. Check it out: https://github.com/kecci/goscription

That’s all for my top 10 framework golang library and additional features.

I hope you enjoy my recommendation, If you have another recommendation, please let me know to comment below.

Thank you !

--

--