How to build one effective middleware?

Constituent parts

The middleware has two parts:

  • part one is what is executed once, when you initialize your middleware. That’s where you set up all the global objects, logicals etc. Everything that happens once per application lifetime.

  • part two is what executes on every request. For example, a database middleware you simply inject your “global” database object into the context. Once it’s inside the context, you can retrieve it from within other middlewares and your handler function.

func funcName(params string) gin.HandlerFunc {
    // <---
    // This is part one
    // --->
    // The following code is an example
    if err := check(params); err != nil {
        panic(err)
    }

    return func(c *gin.Context) {
        // <---
        // This is part two
        // --->
        // The following code is an example
        c.Set("TestVar", params)
        c.Next()    
    }
}

Execution process

Firstly, we have the following example code:

func main() {
	router := gin.Default()

	router.Use(globalMiddleware())

	router.GET("/rest/n/api/*some", mid1(), mid2(), handler)

	router.Run()
}

func globalMiddleware() gin.HandlerFunc {
	fmt.Println("globalMiddleware...1")

	return func(c *gin.Context) {
		fmt.Println("globalMiddleware...2")
		c.Next()
		fmt.Println("globalMiddleware...3")
	}
}

func handler(c *gin.Context) {
	fmt.Println("exec handler.")
}

func mid1() gin.HandlerFunc {
	fmt.Println("mid1...1")

	return func(c *gin.Context) {

		fmt.Println("mid1...2")
		c.Next()
		fmt.Println("mid1...3")
	}
}

func mid2() gin.HandlerFunc {
	fmt.Println("mid2...1")

	return func(c *gin.Context) {
		fmt.Println("mid2...2")
		c.Next()
		fmt.Println("mid2...3")
	}
}

According to Constituent parts said, when we run the gin process, part one will execute firstly and will print the following information:

globalMiddleware...1
mid1...1
mid2...1

And init order is:

globalMiddleware...1
    |
    v
mid1...1
    |
    v
mid2...1

When we curl one request curl -v localhost:8080/rest/n/api/some, part two will execute their middleware and output the following information:

globalMiddleware...2
mid1...2
mid2...2
exec handler.
mid2...3
mid1...3
globalMiddleware...3

In other words, run order is:

globalMiddleware...2
    |
    v
mid1...2
    |
    v
mid2...2
    |
    v
exec handler.
    |
    v
mid2...3
    |
    v
mid1...3
    |
    v
globalMiddleware...3