7
votes

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!

3

3 Answers

15
votes

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))
2
votes

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.

0
votes

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.