Introduction to Gin Framework

Gin is a Web framework written in Go (Golang). It is an API framework similar to martini but with better performance, unlike the Beegoweb framework led by xieda, which is more like the Django framework in Python and contains the components needed to develop a web application.

If you’re a fan of performance and efficiency, I’m sure you’ll fall in love with Gin as MUCH as I do.

At the same time, different from other Golang language API framework, the framework of community is very active, and the main process is still in constantly update and improve, we know that in choosing a normally open source software or related library, community activity as well as the updates of the project will be very important (considering the late maintenance and performance and characteristics of the problem).

On the other hand, the framework officially provides many simple examples to quickly run a desired HTTP service, which is a good start for a student who has just transferred to Golang for business development.

Gin provides official examples of various HTTP services

Of course, FOR a long time, I only looked at the official example to quickly get familiar with and realize my business requirements, but when there are some special requirements, I usually look at the official implementation to meet the requirements, which is not only time-consuming and inefficient for a long time, so I have the interest to explore the core source code. I hope to have an in-depth study of Gin framework through source code.

Several core structures in the Gin framework

As we all know, to develop an HTTP service, we first need to start a TCP listener, and then need to have a series of handlers to deal with the specific business logic. Finally, the specific business logic is bound with the relevant Method and URL through the HTTP protocol agreement, so as to provide the HTTP service with specific functions externally. The Gin framework corresponds to the following models, and we will learn the implementation of Gin together.

There are several important models in the Gin framework:

  • Engine: used to initialize oneginObject instance, which contains some basic functions of the framework, such as logging, middleware Settings, routing control (group), and handlerContext methods.The source code file
  • Router: Defines routing rules and conditions and registers specific routes to a handler implemented by context through HTTP services
  • Context: ContextIs an important point in the framework that allows us to share variables between middleware, manage the entire process, validate the JSON of the request, and provide a JSON response body. Normally our business logic processing is also implemented in the entire Context reference object.
  • Bind: We can obtain the detailed information of the request, such as the HTTP request header and the request body, from the Context, but we need to obtain the corresponding formatted data according to different HTTP protocol parameters to process the underlying business logicBindRelated structural methods to parse HTTP data in context

1. Engine structure in Gin framework

When we use the framework [Gin](https://github.com/gin-gonic/gin) to create an HTTP service, we first need to initialize an instance. The Engine structure contains the basic properties of the instance and the methods of instantiation.

Engine structure:

Struct {// Struct {// struct {// struct {// For example: /apis/,/v1/ etc. RouterGroup // Enable automatic redirect. If the current route does not match, but there is a handler that does not start with /, the route is redirected. Such as: The user enters /foo/ but a /foo is automatically redirected to this handler and returns either a 301 or 307 status code to the client (the difference is between GET and other methods). RedirectTrailingSlash bool When no handler is registered, the route will attempt to fix the current requested address by itself. The first superfluous element is removed (.. / or //); 2. The route searches the new path case insensitive. If the handler is found correctly, the route is redirected to the correct handler and returns either 301 or 307 (e.g. /FOO and /.. //Foo may be redirected to /Foo.) RedirectFixedPath bool // If this parameter is enabled, the route checks whether other methods are allowed if the current request cannot be routed. In this case, "Method Not Allowed" is responded and status code 405 is returned. If no other method is allowed, HandleMethodNotAllowed bool // Whether to forward the client IP ForwardedByClientIP bool // This will add an "X-AppEngine..." to the request. RawPath (default :false) UseRawPath bool // If enabled, the request path will not be escaped. If UseRawPath is false, UnescapePathValues bool Specifies the value of the maxMemory parameter (the parameter used when http.Request ParseMultipartForm is called). MaxMultipartMemory int64 // Whether to remove extra backslashes (at the beginning can parse requests with extra slashes) RemoveExtraSlash // Delims // Set the json prefix in Context.securejson in China SecureJsonPrefix String // Returns an HTMLRender interface (used to render templates for HTMLProduction and HTMLDebug struct types) HTMLRender render FuncMap [string]interface{} in the HTML /template package, which defines the mapping from name to function FuncMap template.FuncMap // Here are some properties internally defined by the GIN framework // HandlersChain is an array of HandlerFunc (HandlerFunc is actually a pointer to a Context, which we'll cover in the next section) allNoRoute HandlersChain allNoMethod HandlersChain noRoute HandlersChain noMethod HandlersChain // this defines a collection of objects that can be accessed temporarily (sync.Pool is thread-safe, mainly used to cache items for use to reduce GC stress, Pool sync. pool // methodTrees are slices of methodTree (methodTree is a structure containing request methods and Pointers to Node, which is a tree of nodes that manages paths) trees methodTrees }Copy the code

HandlerFunc definition:

Handler type HandlerFunc func(*Context)Copy the code

How to initialize Engine:

  • New()This function returns a default Engine reference instance (with automatic redirection enabled, forward client IP, and request path escape disabled)
  • Default(): Internal callNew()Function, but added Logger and Recovery middleware

Engine external common methods:

  • Delims(left, right string) *Engine: Specifies the left and right separator of the template engine for the created gin instance
  • SecureJsonPrefix(prefix string) *Engine: Sets secureJsonPrefixi for the gin instance you have created
  • SetHTMLTemplate(templ *template.Template)This method will actually bind a template engine (inside the engine’s HTMLRender property).
  • LoadHTMLGlob(pattern string)This method is used to load HTML template files in glob patterns (similar to regees in the shell) and associate the results with the HTML template engine (internal call)SetHTMLTemplateMethod to register all matches with the template.
  • LoadHTMLFiles(files ... string)To use this method, you need to specify a set of template file names
  • SetFuncMap(funcMap template.FuncMap)This method sets a FuncMap to template.FuncMap (the FuncMap that actually sets the engine inside).
  • NoRoute(handlers ... HandlerFunc)This method will add some handlers to NoRoute, which will return 404 by default.
  • NoMethod(handlers ... HandlerFunc)This method is used to add handler to NoMethod and returns 405 by default
  • Use(middleware ... HandlerFunc) IRoutesThis method is used to bind a global middleware to the router. Middleware registered with this method will be included in the handler chain of each request (for example, some loggers or error-related middleware can be used here). On which the instance is initializedDefault()Function is actually used internallyengine.Use(Logger(), Recovery())To load logger and recovery middleware
  • Routes() (routes RoutesInfo): Returns a route listRoutesInfoA routing information (RouteInfo contains Method, Path, Handler, HandlerFunc), this Method is called the underlying engine of trees to obtain some necessary information to the router.
  • Run(addr ... string) (err error): This method binds the router to http.Server and enables an HTTP listener to receive HTTP requests. The method is actuallyhttp.ListenAndServe(addr, engine)Note: This method blocks the goroutine call indefinitely unless an error occurs (as long as http.serveHTTP is implemented in engine).
  • RunTLS(addr, certFile, keyFile string) (err error): Run the service in HTTPS mode
  • RunUnix(file string) (err error)With:Run(addr)Method to run the service through the specified Unix socket file
  • RunFd(fd int) (err error)With:Run(addr)Method to run the service with the specified file descriptor (FD)
  • RunListener(listener net.Listener) (err error)With:Run(addr)By makingnet.ListenerTo run the service
  • ServeHTTP(w http.ResponseWriter, req *http.Request): This method is followedhttp.HandlerTo enable gin to be called internallyhttp.ListenAndServeTo start an HTTP service
  • HandleContext(c *Context): this method re-validates a rewritten context(this can be done with c.equest.url.path). It is important to note that this method can cause the context to be used in a loop.

2. Router in Gin framework

It is possible to quickly start an HTTP service using the methods provided in the Engine structure, but how to expose a URL to simply implement an HTTP data transfer requires using the Router method.

Router-related constructs in Gin framework:

  • RouterGroupThis structure is used to configure a route within Gin, and a RouterGroup is used to associate URL prefixes with a specific set of handler business logic
  • IRoutes: IRoutes is an interface that handles all routing (including some common HTTP methods)
  • IRouter: IRouter is an interface that contains all route processing for a single route and a routing group
Handlers HandlersChain basePath string engine * engine root bool Type IRoutes interface {Use(... HandlerFunc) IRoutes Handle(string, string, ... HandlerFunc) IRoutes Any(string, ... HandlerFunc) IRoutes GET(string, ... HandlerFunc) IRoutes POST(string, ... HandlerFunc) IRoutes DELETE(string, ... HandlerFunc) IRoutes PATCH(string, ... HandlerFunc) IRoutes PUT(string, ... HandlerFunc) IRoutes OPTIONS(string, ... HandlerFunc) IRoutes HEAD(string, ... HandlerFunc) IRoutes StaticFile(string, string) IRoutes Static(string, string) IRoutes StaticFS(string, HTTP.FileSystem) IRoutes} // IRouter interface type IRouter interface {IRoutes Group(string,... HandlerFunc) *RouterGroup }Copy the code

Remember from the previous section that we had a RouterGroup field in our Engine structure that helped us initialize a default RouterGroup instance after we created a gin instance of Engine.

For example, the New() function in the Engine structure initializes a GIN instance with the following RouterGroup and registers the GIN instance with the Engine field of the RouterGroup. The source code file

// https://github.com/gin-gonic/gin/blob/master/gin.go#L129
        RouterGroup: RouterGroup{
            Handlers: nil,
            basePath: "/",
            root:     true,
        },Copy the code

Common methods for exposing RouterGroup structures are as follows:

  • Use(middleware ... HandlerFunc) IRoutes: Registers a middleware and returns the Iroutes interface
  • Group(relativePath string, handlers ... HandlerFunc) *RouterGroupThe: Group method creates a new routing Group. Usually we create a common middleware or route with the same prefix to merge into a routing group
  • BasePath() string: this method is used to return a routing Group initial path (e.g. V := router.group (“/rest/n/v1/ API “), where v.basepath () is “/rest/n/v1/ API “).
  • Handle(httpMethod, relativePath string, handlers ... HandlerFunc) IRoutesThis method registers a new handler with the given HTTP method and URL. The last handler should be the actual handler, and the others should be middleware shared between different routes.Note: A private handle(httpMethod, relativePath String, Handlers HandlersChain) method is called internally to handle the core logic
  • POST(relativePath string, handlers ... HandlerFunc) IRoutes: The method isrouter.Handle("POST", path, handle)Fast implementation of,
  • GET(relativePath string, handlers ... HandlerFunc) IRoutes: same as above
  • DELETE(relativePath string, handlers ... HandlerFunc) IRoutes: same as above
  • PATCH(relativePath string, handlers ... HandlerFunc) IRoutes: same as above
  • PUT(relativePath string, handlers ... HandlerFunc) IRoutes: same as above
  • OPTIONS(relativePath string, handlers ... HandlerFunc) IRoutes: same as above
  • HEAD(relativePath string, handlers ... HandlerFunc) IRoutes: same as above
  • Any(relativePath string, handlers ... HandlerFunc) IRoutesAs above, all HTTP methods are registered
  • StaticFile(relativePath, filepath string) IRoutesThis method is used to register a single file that serves the local file system, for example:router.StaticFile("favicon.ico", "./resources/favicon.ico")
  • Static(relativePath, root string) IRoutes: this method is used to provide a route specifying the root path of the file system, called internallygroup.StaticFS(path,Dir(root,false))To provide a service
  • StaticFS(relativePath string, fs http.FileSystem) IRoutes: specifies the FileSystem (http.filesystem) to create a service

3.Gin example

With the above two core models Engine and RouteGroup in mind, we can now quickly create a simple HTTP service using the Gin framework.

The default route

$cat case1.go package main import ("net/ HTTP ""github.com/gin-gonic/gin") func main() {// Use the Default() function to initialize an instance of gin (the reference object of the engine structure) // Call the New() function inside the Default function to initialize an instance of gin, and Use(middleware... The HandlerFunc) IRoutes method registers both Logger and Recovery middleware and also initializes a RouterGroup with bathPath "/" by default when New() initializes gin instances. GinObj := gin.Default() // Since RouterGroup is an anonymous object in engine, Therefore, the instantiated Engine reference object can directly operate on all the methods exposed in the RouterGroup structure HTTP: / / https://github.com/gin-gonic/gin/blob/master/routergroup.go#L133 / / in RouterGroup various foreign exposure method, Handler (httpMethod, relativePath String, Handlers... HandlerFunc) IRoutes method, after which multiple handlers can be passed to handle the specific business logic, when there are more than one handler the last one to handle the actual business request, The previous handler handles middleware and shared components // Whereas HandlerFunc is an anonymous function of func(*Context). Any("/hello",func(c *gin.Context){// Context-related methods will be analyzed in the next section. Here is a simple example of c.struing (http.statusok,"Hello BGBiao.")}) // When all the routes are registered, we can actually run the HTTP service using gin's constructor methods (reference objects to engine constructs), To receive HTTP requests from the user. Ginobj. Run("localhost:8080")} # $go Run case1.go [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] POST /hello --> main.main.func1 (3 handlers) [GIN-debug] PUT /hello --> main.main.func1 (3 handlers) [GIN-debug] PATCH /hello --> main.main.func1 (3 handlers) [GIN-debug] HEAD /hello --> main.main.func1 (3 handlers) [GIN-debug] OPTIONS /hello --> main.main.func1 (3 handlers) [GIN-debug] DELETE /hello --> main.main.func1 (3 handlers) [GIN-debug] CONNECT /hello --> main.main.func1 (3 handlers) [GIN-debug] TRACE /hello --> main.main.func1 (3 handlers) [GIN-debug] Listening and serving $curl localhost:8080/hello hello BGBiao.% $curl -x POST localhost:8080/hello Hello BGBiao.% $ curl -X DELETE localhost:8080/hello Hello BGBiao.% $ curl -X TRACE localhost:8080/hello Hello BGBiao.%Copy the code


Come, hook up 😆!

Welcome to follow my official account: BGBiao, progress together ~