This blog mainly introduces how to build a Go Web server step by step based on Gin, using Go Module as dependency management from scratch. Endless is used to make the server restart smoothly and Swagger is used to automatically generate Api documentation.

Source code here: project source code

You can look at the source code first, and then follow this article to understand some of the details of the server setup process.

Set up the environment

All of the following steps are based on MacOS.

Install the go

Homebrew is recommended for installation here. Of course, you can also use source installation.

brew install go
Copy the code

After running the command, type go on the command line. If the following command output is displayed, the installation is successful.

Go is a tool for managing Go source code.
Usage:
	go <command> [arguments] The commands are: ... .Copy the code

It is important to note that go needs to be at least 1.11 before you can use the Go Module. Here’s my version of Go.

go version
# go version go1.12.5 darwin/amd64
Copy the code

IDE

GoLand is recommended

Configuration GOPATH

Open GoLand, find Global GOPATH in GoLand’s Settings and set it to $HOME/go. The $HOME directory is the user directory of your computer. If there is no go directory in this directory, there is no need to create a go directory. When we initialize the module later, we will automatically create a go directory in the user directory.

To enable the GO Module

Also, find the Go Modules (vgo) in GoLand Settings. Check the check box before Integration to Enable Go Moudle

Build project framework

The new directory

Create a new directory in your regular workspace. If you have a Github project, clone it.

Initialize the Go Module

go mod init $MODULE_NAME
Copy the code

Use the command above to initialize the Go Module in the root directory of the newly created project. This command creates a new go.mod file in the project root directory.

If you clone your project from Github, the $MODULE_NAME parameter is not needed. It defaults to github.com/$GITHUB_USER_NAME/$PROJECT_NAME.

For example, the project is github.com/detectiveHLH/go-backend-starter; If the project is created locally, the last parameter must be added. Otherwise, you will encounter the following error.

go: cannot determine module path for source directory /Users/hulunhao/Projects/go/test/src (outside GOPATH, no import comments)
Copy the code

The contents of the go.mod file after initialization are as follows.

module github.com/detectiveHLH/go-backend-starter

go 1.12
Copy the code

The new main. Go

Create main.go in the root directory of your project. Here’s the code.

package main

import (
	"fmt"
)

func main(a) {
	fmt.Println("This works")}Copy the code

Run the main. Go

Go run main.go in the root directory. If you see This works on the command line, the basic framework has been built. Next we begin to introduce Gin into the framework.

The introduction of Gin

Gin is an HTTP Web Framework implemented with Go, and we use Gin as the Base Framework for starter.

Install the Gin

Install directly with the go get command

go get github.com/gin-gonic/gin
Copy the code

After a successful installation, we can see that the contents of the go.mod file have changed.

Also, we don’t see the dependencies we just installed under GOPATH. In fact, dependencies are installed under $GOPATH/ PKG /mod.

module github.com/detectiveHLH/go-backend-starter

go 1.12

require github.com/gin-gonic/gin v14.. 0 // indirect
Copy the code

A go.sum file is also generated. It reads as follows.

github.com/davecgh/go-spew v11.. 0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0. 0. 0- 20190301062529.- 5545.eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=
github.com/gin-contrib/sse v0. 0. 0- 20190301062529.- 5545.eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
github.com/gin-gonic/gin v14.. 0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
github.com/gin-gonic/gin v14.. 0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
github.com/golang/protobuf v13.1. h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v13.1./go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/json-iterator/go v11.6./go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/mattn/go-isatty v0. 07. h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
github.com/mattn/go-isatty v0. 07./go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/modern-go/concurrent v0. 0. 0- 20180306012644.-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1. 01./go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pmezard/go-difflib v1. 0. 0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v01.. 0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v13.. 0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/ugorji/go v11.4. h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
github.com/ugorji/go v11.4./go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
golang.org/x/crypto v0. 0. 0- 20190308221718.-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0. 0. 0- 20190503192946.-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0. 0. 0- 20190215142949.-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0. 0. 0- 20190222072716.-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v03.. 0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0. 0. 0- 20161208181325.-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/go-playground/assert.v1 v12.1./go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v818.2. h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
gopkg.in/go-playground/validator.v8 v818.2./go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/yaml.v2 v22.2. h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v22.2./go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
Copy the code

As anyone who has used Node knows, a package-lock.json file is generated after a dependency is installed to lock the version of the dependency. To prevent unnecessary bugs when a dependency is reinstalled later and the new version is not compatible with the existing code.

But that’s not what the go.sum file does. We can see that only one Gin dependency is recorded in Go.mod, while there are many in Go.sum. This is because go.mod only records the top-level dependencies that we install directly from the command line. But be aware that an open source package often relies on many other dependencies.

Go.sum is a file that records a specific version of all the top-level and indirect dependencies in it, generating a specific hash value for each dependency version so that when the project is enabled in a new environment, 100% of the project’s dependencies can be restored. Go.sum also keeps some information about versions used in the past.

Under the Go Module, there is no need for a vendor directory to ensure reproducible builds, but rather precise versioning of each dependency in the project through the go.mod file.

If the previous project used Vendor, rewriting with go.mod is not practical. We can use the go mod vendor command to copy all the dependencies of the previous project to the vendor directory. To ensure compatibility, dependencies in the vendor directory are not the same as go.mod. The copied directory does not contain the version number.

As you can see from installing gin above, go.mod files are not required to be manually edited and will automatically update their dependencies and version numbers after executing the command.

Let’s take a look at the go Mod commands.

  • Init Initializes the Go Module
  • Download the dependencies in go.mod to the local cache directory ($GOPATH/ PKG /mod)
  • Edit Edits go.mod to manually upgrade and obtain dependencies from the command line
  • Vendor copies project dependencies to Vendor
  • Tidy install missing dependencies, discard useless dependencies
  • Graph prints the module dependency graph
  • Verify verifies that the dependency is correct

Another command worth mentioning is go list -m all, which lists the build list of the current project.

Modify the main. Go

The code to modify main.go is as follows.

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
)

func main(a) {
	fmt.Println("This works.")
	r := gin.Default()
	r.GET("/hello".func(c *gin.Context) {
		c.JSON(200, gin.H{
			"success": true."code": 200."message": "This works"."data": nil,
		})
	})
	r.Run()
}
Copy the code

The above code introduces routing, which is similar to koa-router if you are familiar with Node.

Start the server

Run Main. go as described above. You can see the following output on the console.

This works.
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /hello                    --> main.main.func1 (3 handlers)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080
Copy the code

At this point, the server has been started on port 8080. Then in the browser to http://localhost:8080/hello, you can see the server returned to normal. At the same time, the server also prints corresponding logs.

[GIN] 2019/06/08-17:41:34 | | 200 | (including 214.213 s: : 1 | GET/helloCopy the code

Build routing

Creating a Routing Module

Create a router directory under the root directory. Under router, create a router.go file with the following code.

package router

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

func InitRouter(a) *gin.Engine {
	router := gin.New()
	apiVersionOne := router.Group("/api/v1/")
	apiVersionOne.GET("hello".func(c *gin.Context) {
		c.JSON(200, gin.H{
			"success": true."code": 200."message": "This works"."data": nil,})})return router
}
Copy the code

In this file, you export an InitRouter function that returns type gin.Engine. The function also defines a GET request that is routed to/API /v1/hello.

Import routes in the main function

Change the code for main.go to the following.

package main

import (
	"fmt"
	"github.com/detectiveHLH/go-backend-starter/router"
)

func main(a) {
	r := router.InitRouter()
	r.Run()
}

Copy the code

Then run the main go, start, go to http://localhost:8080/api/v1/hello, you can see, and access/hello routing result is the same as before.

At this point, we have a Web server with simple functionality. So the problem is, with an open server, as long as you know the address, your server is exposed to someone else. This can lead to some security risks. So we need to authenticate the interface, and only authenticated callers can call the server interface. So next, we need to introduce JWT.

Introduce JWT authentication

Install the JWt-go dependency using the go get command.

go get github.com/dgrijalva/jwt-go
Copy the code

Create a JWT authentication file

Create a new middleware/ JWT directory in the root directory and a new jwt.go file in the JWT directory.

package jwt

import (
  "github.com/detectiveHLH/go-backend-starter/consts"
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
)

func Jwt(a) gin.HandlerFunc {
	return func(c *gin.Context) {
		var code int
		var data interface{}

		code = consts.SUCCESS
		token := c.Query("token")
		if token == "" {
			code = consts.INVALID_PARAMS
		} else {
			claims, err := util.ParseToken(token)
			iferr ! =nil {
				code = consts.ERROR_AUTH_CHECK_TOKEN_FAIL
			} else if time.Now().Unix() > claims.ExpiresAt {
				code = consts.ERROR_AUTH_CHECK_TOKEN_TIMEOUT
			}
		}

		ifcode ! = consts.SUCCESS { c.JSON(http.StatusUnauthorized, gin.H{"code": code,
				"msg":  consts.GetMsg(code),
				"data": data,
			})

			c.Abort()
			return
		}

		c.Next()
	}
}
Copy the code

The introduction of the constants

At this point, there is an error in the code because we did not declare the consts package, and the variables SUCCESS, INVALID_PARAMS, and ERROR_AUTH_CHECK_TOKEN_FAIL are undefined. The function GetMsg, which gets information from the server according to code, is also undefined. Also undefined are util.parseToken (token) and Claim.expiresat. So we’re going to create a new Consts package. Create a new consts directory under the root directory, and create a new code.go directory under the consts directory, and import some constants defined as follows.

New const file

const (
	SUCCESS        = 200
	ERROR          = 500
	INVALID_PARAMS = 400
)
Copy the code

Creating a Message file

Create a new message.go file with the following code.

var MsgFlags = map[int]string{
	SUCCESS:                         "ok",
	ERROR:                           "fail",
	INVALID_PARAMS:                  "Request parameter error",}func GetMsg(code int) string {
	msg, ok := MsgFlags[code]
	if ok {
		return msg
	}
	return MsgFlags[ERROR]
}
Copy the code

New util

Create a new util under the root directory and a new jwt.go under util as follows.

package util

import (
	"github.com/dgrijalva/jwt-go"
	"time"
)

var jwtSecret = []byte(setting.AppSetting.JwtSecret)

type Claims struct {
	Username string `json:"username"`
	Password string `json:"password"`
	jwt.StandardClaims
}

func GenerateToken(username, password string) (string, error) {
	nowTime := time.Now()
	expireTime := nowTime.Add(3 * time.Hour)
	claims := Claims{
		username,
		password,
		jwt.StandardClaims {
			ExpiresAt : expireTime.Unix(),
			Issuer : "go-backend-starter",
		},
	}
	tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	token, err := tokenClaims.SignedString(jwtSecret)

	return token, err
}

func ParseToken(token string) (*Claims, error) {
	tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return jwtSecret, nil
	})
	iftokenClaims ! =nil {
		if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
			return claims, nil}}return nil, err
}
Copy the code

Setting new package

In util above, the setting package is not defined, so we need to define the setting package in this step.

Use the go get command to install dependencies.

go get gopkg.in/ini.v1
Copy the code

Create setting directory under the root directory of the project, and create setting.go file under the setting directory. The code is as follows.

package setting

import (
	"gopkg.in/ini.v1"
	"log"
)

type App struct {
	JwtSecret string
}
type Server struct {
	Ip   string
	Port string
}
type Database struct {
	Type        string
	User        string
	Password    string
	Host        string
	Name        string
	TablePrefix string
}

var AppSetting = &App{}
var ServerSetting = &Server{}
var DatabaseSetting = &Database{}
var config *ini.File

func Setup(a) {
	var err error
	config, err = ini.Load("config/app.ini")
	iferr ! =nil {
		log.Fatal("Fail to parse 'config/app.ini': %v", err)
	}
	mapTo("app", AppSetting)
	mapTo("server", ServerSetting)
	mapTo("database", DatabaseSetting)
}

func mapTo(section string, v interface{}) {
	err := config.Section(section).MapTo(v)
	iferr ! =nil {
		log.Fatalf("Cfg.MapTo RedisSetting err: %v", err)
	}
}
Copy the code

Creating a Configuration File

Create the config directory under the project root directory and create the app.ini file with the following contents.

[app]
JwtSecret = 233
[server]
Ip : localhost
Port : 8000
Url : 127.0.0.1:27017
[database]
Type = mysql
User = $YOUR_USERNAME
Password = $YOUR_PASSWORD
Host = 127.0.0.1:3306
Name = golang_test
TablePrefix = golang_test_
Copy the code

Implementing the login interface

Adding a Login Interface

At this point, the logic for authentication through the JWT token is complete, and all that remains is to implement the login interface to return the token to the user upon successful login.

Use the go get command to install dependencies.

go get github.com/astaxie/beego/validation
Copy the code

Create login.go under the router with the following code.

package router

import (
	"github.com/astaxie/beego/validation"
	"github.com/detectiveHLH/go-backend-starter/consts"
	"github.com/detectiveHLH/go-backend-starter/util"
	"github.com/gin-gonic/gin"
	"net/http"
)

type auth struct {
	Username string `valid:"Required; MaxSize(50)"`
	Password string `valid:"Required; MaxSize(50)"`
}


func Login(c *gin.Context) {
	appG := util.Gin{C: c}
	valid := validation.Validation{}
	username := c.Query("username")
	password := c.Query("password")

	a := auth{Username: username, Password: password}
	ok, _ := valid.Valid(&a)
	if! ok { appG.Response(http.StatusOK, consts.INVALID_PARAMS,nil)
		return
	}

	authService := authentication.Auth{Username: username, Password: password}
	isExist, err := authService.Check()
	iferr ! =nil {
		appG.Response(http.StatusOK, consts.ERROR_AUTH_CHECK_TOKEN_FAIL, nil)
		return
	}

	if! isExist { appG.Response(http.StatusOK, consts.ERROR_AUTH,nil)
		return
	}

	token, err := util.GenerateToken(username, password)
	iferr ! =nil {
		appG.Response(http.StatusOK, consts.ERROR_AUTH_TOKEN, nil)
		return
	}

	appG.Response(http.StatusOK, consts.SUCCESS, map[string]string{
		"token": token,
	})
}
Copy the code

New Return class

Add response.go file under util package, the code is as follows.

package util

import (
	"github.com/detectiveHLH/go-backend-starter/consts"
	"github.com/gin-gonic/gin"
)

type Gin struct {
	C *gin.Context
}

func (g *Gin) Response(httpCode, errCode int, data interface{}) {
	g.C.JSON(httpCode, gin.H{
		"code": httpCode,
		"msg":  consts.GetMsg(errCode),
		"data": data,
	})

	return
}
Copy the code

Added authentication logic

In addition to the return classes, there are key authentication logic in login.go that has not been implemented. Create the service/authentication directory in the root directory and create the auth.go file in this directory. The code is as follows:

package authentication

import "fmt"

type Auth struct {
	Username string
	Password string
}

func (a *Auth) Check(a) (bool, error) {
	userName := a.Username
	passWord := a.Password
  // todo: implements its own authentication logic
	fmt.Println(userName, passWord)
	return true.nil
}
Copy the code

Here, you really need to implement the validity check of the user call interface according to the business. For example, you can authenticate a user to a database based on the user name and password.

Modify the router. Go

Modify the router.go code as follows.

package router

import (
	"github.com/detectiveHLH/go-backend-starter/middleware/jwt"
	"github.com/gin-gonic/gin"
)

func InitRouter(a) *gin.Engine {
	router := gin.New()

	router.GET("/login", Login)
	apiVersionOne := router.Group("/api/v1/")
  
	apiVersionOne.Use(jwt.Jwt())
  
	apiVersionOne.GET("hello".func(c *gin.Context) {
		c.JSON(200, gin.H{
			"success": true."code": 200."message": "This works"."data": nil,})})return router
}
Copy the code

As you can see, we added the /login interface to the routing file and used our custom JWT authentication middleware. As long as the route is under V1, the JWT is used for authentication before the request is made. After the authentication succeeds, the route can be continued.

Run the main. Go

To this, we use the go run main. Go to start the server, http://localhost:8080/api/v1/hello will encounter the following error.

{
    "code": 400."data": null,
    "msg": "Request parameter error"
}
Copy the code

This is because we have added authentication, and all interfaces that need authentication need to carry parameter token. In order to obtain the token, we must log in first. Assume that our user name is Tom and password is 123. To invoke the login interface.

http://localhost:8080/login?username=Tom&password=123
Copy the code

After accessing the above URL in your browser, you can see the following return.

{
    "code": 200."data": {
        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IlRvbSIsInBhc3N3b3JkIjoiMTIzIiwiZXhwIjoxNTYwMTM5MTE3LCJpc3MiOiJnby 1iYWNrZW5kLXN0YXJ0ZXIifQ.I-RSi-xVV1Tk_2iBWolF1u94Y7oVBQXnHh6OI2YKJ6U"
    },
    "msg": "ok"
}
Copy the code

After we have the token, we can call the Hello interface again and see that the data is returned normally.

http://localhost:8080/api/v1/hello?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IlRvbSIsInBhc3N3b3JkIjoiMT IzIiwiZXhwIjoxNTYwMTM5MTE3LCJpc3MiOiJnby1iYWNrZW5kLXN0YXJ0ZXIifQ.I-RSi-xVV1Tk_2iBWolF1u94Y7oVBQXnHh6OI2YKJ6U
Copy the code

Typically, the front end takes the token, stores it in a persistent store, and sends the token to the back end in a header on every subsequent request. The backend uses the token in the header to verify the validity of the calling interface, and then invokes the interface.

Here I put the token in request Param, just to show you an example.

The introduction of swagger

With the basic framework in place, we start importing Swagger documents for our interfaces. Those of you who have written Java are familiar with Swagger. I usually write API documents by hand. That is, each parameter of each interface needs to be manually typed.

Swagger, on the other hand, automatically generates a Swagger document for you just by making a few annotations on the interface (in Java). In GO, we do this by way of comments. Next we install gin-Swagger.

Install dependencies

go get github.com/swaggo/gin-swagger
go get -u github.com/swaggo/gin-swagger/swaggerFiles
go get -u github.com/swaggo/swag/cmd/swag
go get github.com/ugorji/go/codec
go get github.com/alecthomas/template
Copy the code

Inject swagger into the router

After introducing dependencies, we need to inject swagger into router/router.go. Add _ in the import of “github.com/detectiveHLH/go-backend-starter/docs.”

Add the following code to router := gin.New().

router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
Copy the code

Write swagger annotations for interfaces

Add the following comment above the login function in router/login.go.

/ / @ the Summary to log in
// @Produce json
// @Param username query string true "username"
// @Param password query string true "password"
// @Success 200 {string} json "{"code":200,"data":{},"msg":"ok"}"
// @Router /login [get]
Copy the code

Initialize the swagger

Use the swag init command in the project root to initialize the Swagger document. This command will generate the docs header in the project root directory, which looks like this.

. ├ ─ ─ docs. Go ├ ─ ─ swagger. Json └ ─ ─ swagger. YamlCopy the code

View the Swagger documentation

Run the main. Go, and then visit http://localhost:8080/swagger/index.html in the browser can see swagger according to comments to automatically generate the API documentation.

The introduction of Endless

Install the Endless

go get github.com/fvbock/endless
Copy the code

Modify the main. Go

package main

import (
	"fmt"
	"github.com/detectiveHLH/go-backend-starter/router"
	"github.com/fvbock/endless"
	"log"
	"syscall"
)

func main(a) {
	r := router.InitRouter()

  address := fmt.Sprintf("%s:%s", setting.ServerSetting.Ip, setting.ServerSetting.Port)
	server := endless.NewServer(address, r)
	server.BeforeBegin = func(add string) {
		log.Printf("Actual pid is %d", syscall.Getpid())
	}

  err := server.ListenAndServe()
	iferr ! =nil {
		log.Printf("Server err: %v", err)
	}
}
Copy the code

Write in the back

Instead of dependency management without the Go Module, the Go Module is now more like package.json in Node.js, or pom.xml in Java, except that pom.xml needs to be manually updated.

When we get the Go Module project, we don’t have to worry about compatibility issues due to version issues when we get dependencies. You can install all version-specific dependencies directly using the go mod command, similar to NPM install in Node.js.

Go module locates modules in the same way that Node.js looks for dependencies. Node will start in the directory where the command is executed and work its way up to node_modules until it finds one. Go looks up the go.mod file in turn to locate a module.

I believe that the dependency management after GO will be better and better.

Happy hacking.

Reference:

  • Explore go Modules again: Use and details
  • go-gin-example
  • Smooth restart

Previous articles:

  • How to integrate JWT(JSON Web Token) authentication in SpringBoot
  • Build SpringBoot backend project framework from scratch

Related:

  • Personal website: Lunhao Hu
  • Wechat official account: full stack notes of SH (or directly search wechat LunhaoHu in the interface of adding official account)