CLI command (spf13 / cobra)

Do you want to generate some CLI commands? Cobra is both a library for creating powerful modern CLI applications and a program for generating application and command files. I use this library to manage the command application, execute the Runner application, initialize the configuration, and launch the Rest API. Cobra based application organization structure:

├ ─ ─ app │ ├ ─ ─ main. Go │ ├ ─ ─ CMD │ └ ─ ─ root. GoCopy the code

In the app/main. Go in:

package main
import (
   "app/cmd"
)
func main() {
   cmd.Execute()
}
Copy the code

In the app/CMD/root. Go in:

package cmd var 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) } }Copy the code

Cobra:github.com/spf13/cobra

Configure reader (SPF13 /viper)

Viper is a complete Go application configuration solution. Viper can read the following:

  • JSON
  • TOML
  • YAML
  • HCL
  • INI
  • Envfile and the Java property configuration file

The sample config/config. Toml:

address="localhost"
port="9090"
Copy the code

Read the 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)) } }Copy the code

Use the value in config in main.go:

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

Viper:github.com/spf13/viper

Web framework (Labstack/Echo) picture

High-performance, minimalist Go Web Framework installation:

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

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!")
}
Copy the code

Dependency injection (Ubergo/FX)

I find this library very useful, you don’t need to generate anything. Just code. Very modular, very hierarchical. A dependency injection based Go application framework.

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, )}Copy the code

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

Swagger generator, UI, and validation

In the Swagger section, I had to use 3 different libraries because I couldn’t find any library that could contain 3 libraries in one library.

A. Swagger Generator (Swaggo/SWAg)

Swag converts the Go annotation to Swagger document 2.0.

We have created various plug-ins for the popular Go Web framework. This allows you to quickly integrate with existing Go projects (using the Swagger UI). Supported Web frameworks:

  • gin
  • echo
  • buffalo
  • net/http

Swag already processes your Swagger document. So you no longer need to write swagger. Yml or swagger. Json. All you need to do is write comments. Here’s 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 [email protected]
// @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))
    ...
}
Copy the code

swaggo/swag:github.com/swaggo/swag

b. Swagger UI (swaggo/echo-swagger)

Since I use echo, I chose this as the user interface for Swagger.

Example:

package main import ( "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: / / http://www.swagger.io/support / / @ contact. Email [email protected]. / / @ license name Apache 2.0 / / @ license. Url HTTP: / / 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")) }Copy the code

Swaggo/echo-swagger:github.com/swaggo/echo…

C. Swagger verification (Go-Swagger/Go-Swagger)

This package contains the Golang implementation of Swagger 2.0 (aka OpenAPI 2.0) : it knows how to serialize and deserialize the Swagger specification. Installation:

go get github.com/go-swagger/go-swagger/cmd/swagger
Copy the code

Type this command to verify:

swagger validate api/docs/swagger.yaml
Copy the code

Output:

2021/01/30 22:47:01 The Swagger spec at "API /docs/ Swagger. Yaml" is valid against Swagger Specification 2.0Copy the code

Go-swagger/go-swagger:github.com/go-swagger/…

Custom loggers (Sirupsen/Logrus)



Logrus is a structured logger for Go(Golang) that is fully API compatible with standard library loggers.

Example:

package main
import (
  log "github.com/sirupsen/logrus"
)
func main() {
  log.WithFields(log.Fields{
    "animal": "walrus",
  }).Info("A walrus appears")
}
Copy the code

Sirupsen/logrus:github.com/sirupsen/lo…

Simulation Generator (Vektra/SHANzhai)

Golang simulation code automatic generator installation:

go get github.com/vektra/mockery/v2/... /Copy the code

Generation simulation:

./bin/mockery --all
Copy the code

Output:





vektra/mockery:Github.com/vektra/mock…

Migration (golang – migrate/migrate)

Database migration written in Go. Used as CLI or imported as library.

Database driver runs migration:

  • 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
Copy the code

Type the command to create the migration file:

migrate create -ext sql -dir database/migrations -seq create_user
Copy the code

Type the command to run the migration:

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

Type the command to interrupt the migration:

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

Golang-migrate/migrate:github.com/golang-migr…

Message Passing (NSQ)

NSQ topology:



NSQ components:

  • Nsqlookupd (Daemon Management topology/Routing)
  • NSQD (daemon manages receiving, queuing, and delivering messages)
  • Nsqadmin (default Web UI for NSQ)

Docker-compose example :(nsqlookupd, NSQD, nsqadmin)

version: '3'
services:
nsqlookupd:
image: nsqio/nsq
command: /nsqlookupd
ports:
- "4160:4160"
- "4161:4161"
nsqd:
image: nsqio/nsq
command: /nsqd --lookupd-tcp-address=nsqlookupd:4160
depends_on:
- nsqlookupd
ports:
- "4150:4150"
- "4151:4151"
nsqadmin:
image: nsqio/nsq
command: /nsqadmin --lookupd-http-address=nsqlookupd:4161
depends_on:
- nsqlookupd
ports:
- "4171:4171"
Copy the code

Perform:

Docker: $docker-compose up -d or, if using the name (docker-compose-nsq.yml) : $docker-compose -f docker-compose-nsq.yml up -d check docker: $docker-compose ps Check $docker - compose logs NSQ Web UI (assuming that port 32770) : $curl http://127.0.0.1:32770/pingCopy the code

In golang:

├── get out, get out, get out, get outCopy the code

Consume. Go:

package main import ( "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 = Arthur c. onnectToNSQD (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() }Copy the code

Run the consume. Go:

$ go run consume/consume.go
Copy the code

The publish. Go:

package main import ( "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) }Copy the code

Run the publish. Go:

$ go run publish/publish.go
Copy the code

Nsqio/go-nsq:github.com/nsqio/go-ns…

SQL (jmoiron/sqlx)

SQLX is a library that provides a set of extensions on top of Go’s standard Database/SQL library.

One thing I like about SQLX is that they can do structural scanning. Quick and easy to use.

Structural scan examples:

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) }Copy the code

Jmoiron/sqlx:github.com/jmoiron/sql…

additional

Go routine grouping (sync/errgroup) pkg.go.dev/golang.org/… Generate smooth SQL (Masterminds/ Squirrel) for Golang. Github.com/Masterminds… Golang Linter (golangci/golangci – lint) github.com/golangci/go… Circuit breakers (Gojek/Heimdall) github.com/gojek/heimd… Go tools generate tags (Fatih/GomodifyTags) github.com/fatih/gomod…

conclusion

To build applications, we should know what features we have, especially if we want to build ongoing applications and collaboration between teams. I recommend having a solid, readable code that is easier to maintain before it becomes legacy code (maybe 5 to 10 years from now). Three keys to building an app:

  • Simple Design (project structure and dependencies)
  • Clean code (readable and maintainable)
  • Modularization (solid and flexible skeleton)