In the last article we modified the routing group

package routes

//routes/routes.go

import (
	"github.com/gin-gonic/gin"
	"myGin/controller"
)

func Load(r *gin.Engine) {

	router := newRouter(r)

	router.Group("/api".func(api group) {

		api.Group("/user".func(user group) {

			user.Registered(GET, "/info", controller.Index)
			user.Registered(GET, "/order", controller.Index)
			user.Registered(GET, "/money", controller.Index)

		})

	})

}
Copy the code

But there’s a problem with writing this, we can’t use middleware, we need to fix it to support middleware and the middleware context is our actual context.

Start by defining HandlerFunc as a middleware function in the context

package context

//context/context.go

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

type Context struct {
	*gin.Context
}

type HandlerFunc func(*Context)

func (c *Context) Domain(a) string {

	return c.Request.Host[:strings.Index(c.Request.Host, ":")]}Copy the code

Then modify router.go and add middleware parameters

package routes

////routes/router.go

import (
	"github.com/gin-gonic/gin"
	"myGin/context"
	"myGin/response"
)

type router struct {
	engine *gin.Engine
}

type group struct {
	engine      *gin.Engine
	path        string
	middlewares []context.HandlerFunc
}

type method int

const (
	GET    method = 0x000000
	POST   method = 0x000001
	PUT    method = 0x000002
	DELETE method = 0x000003
	ANY    method = 0x000004
)

func newRouter(engine *gin.Engine) *router {

	return &router{
		engine: engine,
	}
}

func (r *router) Group(path string, callback func(group).middlewares.context.HandlerFunc) {

	callback(group{
		engine:      r.engine,
		path:        path,
		middlewares: middlewares,
	})

}

func (g group) Group(path string, callback func(group).middlewares.context.HandlerFunc) {

	// Note that the parent middleware comes first
	g.middlewares = append(g.middlewares, middlewares...)

	g.path += path

	callback(g)
}

func (g group) Registered(method method, url string, action func(*context.Context) *response.Response.middlewares.context.HandlerFunc) {

	// Parent middleware + current action middleware +action
	var handlers = make([]gin.HandlerFunc, len(g.middlewares)+len(middlewares)+1)

	// Add the current action's middleware
	g.middlewares = append(g.middlewares, middlewares...)

	// Convert the middleware to gin.HandlerFunc
	for key, middleware := range g.middlewares {

		temp := middleware

		handlers[key] = func(c *gin.Context) {

			temp(&context.Context{Context: c})
		}
	}

	/ / add the action
	handlers[len(g.middlewares)] = convert(action)

	finalUrl := g.path + url

	switch method {

	case GET:

		g.engine.GET(finalUrl, handlers...)

	case POST:

		g.engine.GET(finalUrl, handlers...)

	case PUT:

		g.engine.PUT(finalUrl, handlers...)

	case DELETE:

		g.engine.DELETE(finalUrl, handlers...)

	caseANY: g.engine.Any(finalUrl, handlers...) }}func convert(f func(*context.Context) *response.Response) gin.HandlerFunc {

	return func(c *gin.Context) {

		resp := f(&context.Context{Context: c})

		data := resp.GetData()

		switch item := data.(type) {

		case string:

			c.String(200, item)

		case gin.H:

			c.JSON(200, item)

		}

	}

}

Copy the code

The implementation principle is to continuously add parent middleware through callback, count all middleware quantity in Registered, and add route to GIN after conversion.

Let’s test it out

Create the Middleware directory in your project and create middleware.go

package middleware

//middleware/middleware.go

import (
	"fmt"
	"myGin/context"
)

func M1(c *context.Context) {

	fmt.Println("I am 1")}func M2(c *context.Context) {

	fmt.Println("I'm a 2")}func M3(c *context.Context) {

	fmt.Println("I'm a 3")}Copy the code


package routes

//routes/routes.go

import (
	"github.com/gin-gonic/gin"
	"myGin/controller"
	"myGin/middleware"
)

func Load(r *gin.Engine) {

	router := newRouter(r)

	router.Group("/api".func(api group) {

		api.Group("/user".func(user group) {

			user.Registered(GET, "/info", controller.Index, middleware.M3)
			user.Registered(GET, "/order", controller.Index)
			user.Registered(GET, "/money", controller.Index)

		}, middleware.M2)

	}, middleware.M1)

}
Copy the code

Run browser, console print

In general, Web frameworks come with some global middleware, such as global error capture middleware, which we continue to encapsulate

Start by creating an error-catching middleware

package exception

import (
	"fmt"
	"myGin/context"
	"runtime/debug"
)

func Exception(c *context.Context) {

	defer func(a) {
		if r := recover(a); r ! =nil {

			msg := fmt.Sprint(r) + "\n" + string(debug.Stack())

			c.String(500, msg)

			c.Abort()
		}

	}()
	c.Next()
}
Copy the code

Create a kernel under the project and create the kernel.go file

package kernel

import (
	"myGin/context"
	"myGin/middleware/exception"
)

// Middleware Global Middleware
var Middleware []context.HandlerFunc

func Load(a) {

	Middleware = []context.HandlerFunc{
		exception.Exception,
	}

}
Copy the code

Load the global middleware in main.go

package main

import (
	"github.com/gin-gonic/gin"
	"myGin/kernel"
	"myGin/routes"
)

func main(a) {
	r := gin.Default()

	// Load global variables
	kernel.Load()

	routes.Load(r)

	r.Run()
}
Copy the code

Let’s change routes.go

package routes

//routes/routes.go

import (
	"github.com/gin-gonic/gin"
	"myGin/controller"
	"myGin/kernel"
)

func config(router group) {

	router.Group("/api".func(api group) {

		api.Group("/user".func(user group) {

			user.Registered(GET, "/info", controller.Index)
			user.Registered(GET, "/order", controller.Index)
			user.Registered(GET, "/money", controller.Index)

		})

	})

}

func Load(r *gin.Engine) {

	router := newRouter(r)

	router.Group("".func(g group) {

		config(g)
	}, kernel.Middleware...) // Load global middleware

}
Copy the code

The main idea is to use an empty route to load a global middleware to this empty route

Modify index controller to simulate an error

package controller

//controller/Index.go

import (
	"myGin/context"
	"myGin/response"
)

func Index(context *context.Context) *response.Response {

	panic("Pretending to be wrong")

	return response.Resp().String(context.Domain())
}
Copy the code

Accessing the browser

Source code address: github.com/PeterYangs/…