'Gin-Gonic middleware declaration

I'm using Gin-Gonic and I'm creating a custom middleware. See: https://github.com/gin-gonic/gin#custom-middleware

Is there a reason why the middlewares in the doc are written as such:

func MyMiddleware() gin.HandlerFunc {
    return func (c *gin.Context) {
        // middleware
    }
}
r := gin.New()
r.Use(MyMiddleware())

When I could simply write it like this:

func MyMiddleware(c *gin.Context) {
    // middleware
}
r := gin.New()
r.Use(MyMiddleware)

Thanks for your help!



Solution 1:[1]

You can certainly just do this if you prefer it:

func MyMiddleware(c *gin.Context) {
    // middleware
}
r := gin.New()
r.Use(MyMiddleware)

The most probably reason why it is suggested that you do this instead:

func MyMiddleware() gin.HandlerFunc {
    return func (c *gin.Context) {
        // middleware
    }
}
r := gin.New()
r.Use(MyMiddleware())

is, so you can add parameters, the example used in here: https://github.com/gin-gonic/gin#custom-middleware is a logging middleware.:

func Logger() gin.HandlerFunc {
    return func(c *gin.Context) {
        // code goes here
    }
}

It didn't have any params, but you can use custom logger like logrus inside your middleware by adding a param:

You can have a logging middleware like this:

func Logger(log *logrus.Logger) gin.HandlerFunc {
    return func(c *gin.Context) {
        // use logrus
        log.WithFields(log.Fields{
          "animal": "walrus",
        }).Info("A walrus appears")

    }
}

And use it like this:

var log = logrus.New()
r.Use(Logger(log))

Solution 2:[2]

Yes, you can.

Sometimes a middleware takes arguments. For example:

MyMiddleware(foo string) gin.HandlerFunc {

    // preprocess with argument foo

    return func(c *gin.Context) {
        // do something related with foo...
    }
}

Take gin.BasicAuthForRealm for example. Before checking the authorization from HTTP requests, you must provide it the auth data.

func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
    // ...
}

For middlewares taking no argument, I think they just want to keep them in same format.

Solution 3:[3]

The variant returning a function, could also allow the middleware to perform some initialization, if needed:

func MyMiddleware() gin.HandlerFunc {
    // Perform initialization here...
    return func (c *gin.Context) {
        // middleware
    }
}

r := gin.New()
r.Use(MyMiddleware())

That initialization would execute only once (when the middleware is attached to the request), and not for every request.

Could be useful, if you are writing a middleware that requires initialization, but you have no control on how others will use it.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Hunsin
Solution 3 quasoft