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:
- PostgreSQL
- Redshift
- Ql
- Cassandra
- SQLite (todo #165)
- SQLCipher
- MySQL/ MariaDB
- Neo4j
- MongoDB
- CrateDB (todo #170)
- Shell (todo #171)
- Google Cloud Spanner
- CockroachDB
- ClickHouse
- Firebird
- MS SQL Server
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
- nsqlookupd (daemon manage topologies / routes)
- nsqd (daemon manage receives, queues, and delivers messages)
- 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 -dTo check container docker:
$ docker-compose psTo see logs:
$ docker-compose logsTo 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:
- Simple Design (Project structure & dependencies)
- Clean Code (Readable & maintainable)
- 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 !