An overview,

1, the introduction of
  • Go official to support Web development, providednet/httpKit; However, in actual projects, the team will still choose a more efficient and convenient Web framework, such asGin,Echo.BeegoAnd so on;
  • Of those teams, many choseGinThis frame, it’s innet/httpIs optimized on the basis of; Compared to other mainstream frameworks, itBetter performanceandFaster Routing;
2. Advantages of Gin
  • Fast: Routing based on Radix tree, performance is very powerful.

  • Support middleware: built-in many middleware, such as the Logger, Gzip, Authorization, etc.

  • Crash recovery: You can catch program crashes caused by panic and keep the Web service running.

  • JSON validation: You can validate the JSON data format in the request.

  • Routing group: Supports routing groups, facilitating route organization.

  • Error management mechanism: Can collect errors in the program

  • Multiple data rendering methods: Support HTML, JSON, YAML, XML and other data formats for response.

  • Extensibility: Very simple to extend middleware.

  • Data validator: Data validators are supported and can be customized.

Gin Simple Demo
package main

import (
	"github.com/gin-gonic/gin"
    "net/http"
)

func setupRouter(a) *gin.Engine {

	r := gin.Default()
	// Ping test
	r.GET("/ping".func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"status" : 0."msg" 	 : "success"."data"   :  gin.H {
				"content" : "pong",}})})return r
}

func main(a) {
   r := setupRouter()
   r.Run() 
}
Copy the code

Gin Simple Demo interpretation

As you can see from Demo Code, the experience of using Gin is very smooth. There are four steps to define how to handle Web requests: import packages, define routes, write handlers, and listen on ports.

1. Import packages
import "github.com/gin-gonic/gin"
Copy the code
2. Define routes
  • Gin.Engine is a routing Engine that is commonly usedgin.Default()Method is created and returnedGin. Engine instance.
r := gin.Default() R uses Logger and Recovery middleware by default
Copy the code

Note: You can use the gin-.new () method to create and return an instance of gin-.engine without any middleware

3. Write a Handler

With the default route, we can create methods to handle HTTP requests, using the GET method in our example:

// Ping test
r.GET("/ping".func(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
			"status" : 0."msg" 	 : "success"."data"   :  gin.H {
				"content" : "pong",}})})Copy the code
  • The underlying implementation of the Get method is the callRouterGroupthehandleThe request processing method is usedHandlerFuncType method
// GET is a shortcut for router.Handle("GET", path, handle).
func (group *RouterGroup) GET(relativePath string, handlers ... HandlerFunc) IRoutes {
	return group.handle("GET", relativePath, handlers)
}

// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context)
Copy the code
  • Note: Gin supports all common HTTP request methods, such asGET.POST.PUT.PATCH.OPTIONS.HEAD.DELETE.
4. Listen to the port
  • Once the request is defined, the port listens for HTTP requests using the Run() method, which listens on port 8080 by default if the Run() method takes no arguments.
r.Run() 
Copy the code
  • The underlying implementation key of the Run method is:http.ListenAndServe, where: HTTP fromnet/httpThe package.
func (engine *Engine) Run(addr ...string) (err error) {
	defer func(a) { debugPrintError(err) }()

	address := resolveAddress(addr)
	debugPrint("Listening and serving HTTP on %s\n", address)
	//
	err = http.ListenAndServe(address, engine)
	return
}
Copy the code

Important data structures in Gin

In Gin Simple Demo Code, we found three important Go data structures: Gin.Engine, Gin.Context, and Gin

1, gin. Engine
  • Gin.Engine is the portal to the framework; The Engine object is used to define service routing information, assemble plug-ins, run services, and drive the entire Web service.
// Engine is the framework's instance, it contains the muxer, middleware and configuration settings.
// Create an instance of Engine, by using New() or Default()
type Engine struct {
	RouterGroup
	
	//....
}
Copy the code
  • Gin.Engine is essentially a wrapper around the built-in HTTP server, making it easier to use.
  • The gin.Default() function generates a Default Engine object containing two Default plugins, Logger and Recovery. Logger is used for logging requests. Recovery ensures that an exception stack log is logged when a panic occurs in a single request and a unified error response is output (It is recommended to use).
func Default(a) *Engine {
   debugPrintWARNINGDefault()
   engine := New()
   engine.Use(Logger(), Recovery())
   return engine
}
Copy the code
  • The gin.New() function generates a default Engine object that does not contain any instances of the middleware.
2, gin. The Context
  • The request context information object, which is the entry parameter to all request handlers.gin.ContextIs defined as follows:
Context allows us to pass variables between middleware, manage flows, validate requested JSON, and return JSON
type Context struct {
	// Request object
	Request   *http.Request
    
    // used to respond
    writermem responseWriter
	Writer    ResponseWriter
 	// Parameters in the URL, such as: /xx/:id
	Params   Params
	
     // Participating handlers (middleware + request handler list)
    handlers HandlersChain
    // The subscript of the handler currently being processed
    index    int8

	fullPath string
	
    / / Engine singleton
	engine *Engine

	// The value that can be set in context
	Keys map[string]interface{}

	// A series of errors
	Errors errorMsgs

	// Define a set of manually accepted formats for content negotiation.
	Accepted []string

	// queryCache use url.ParseQuery cached the param query result from c.Request.URL.Query()
	queryCache url.Values

	// formCache use url.ParseQuery cached PostForm contains the parsed form data from POST, PATCH,
	// or PUT body parameters.
	formCache url.Values
}
Copy the code
  • Context the Context object is not generated every time, but is retrieved from the object pool; The real processing core of the request lies inhandleHTTPRequestIn a function.
  • The core logic in the handleHTTPRequest function is to find and call an array of functions to handle (including the handlers we defined, as well as those in the middle tier) based on the request method and the request URI.
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {

	// Get a context object from the object pool
	c := engine.pool.Get().(*Context)

	// Initialize the context object, because the data from the object pool has dirty data, so initialize it.
	c.writermem.reset(w)
	c.Request = req
	c.reset()

    // Process web requests (HTTP request processing)
	engine.handleHTTPRequest(c)

	// The Context object is thrown back into the object pool
	engine.pool.Put(c)
}
Copy the code
3, gin. RouterGroup
  • A RouterGroup is a routing group that wraps a route tree and manages all routing rules. The Engine structure inherits from the RouterGroup, so the Engine directly provides all route management functions of the RouterGroup.
// RouterGroup is used internally to configure router, a RouterGroup is associated with
// a prefix and an array of handlers (middleware).
type RouterGroup struct {
	Handlers HandlersChain
	basePath string
	engine   *Engine
	root     bool
}

// HandlersChain defines a HandlerFunc array.
type HandlersChain []HandlerFunc
Copy the code
  • The RouteGroup objects include basePath (prefix path), Engine Pointers and Handlers(array of functions).

  • RouterGroup implements a set of routing methods defined by the IRouter interface. These methods ultimately hook the request handler into the routing tree by calling the engine.addroute method.

  • A RouterGroup has a prefix path attribute that prefixes all subpaths into the routing tree. With this prefix path, you can implement URL grouping. The Engine object’s built-in RouterGroup object has a prefix path of /, which represents the root path. RouterGroup supports Group nesting. You can use the Group method to attach groups to a RouterGroup.

    v1 := r.Group("/api/v1")
    {
    	v1.POST("/submit",submit)
    	v1.GET("/list",list)
    }
    // The RouterGroup object of the Engine object is the first-layer group (the root group). V1 is a subgroup of the root group.
    Copy the code
4, gin. H
  • Gin.H is a shortcut name for map[string]interface{}.
type H map[string]interface{}
Copy the code