4

Given:

package main

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

func main() {
    r := gin.Default()
    r.POST("/status", handler)
    r.Run(":8080")
}

func handler(c *gin.Context) {

    var status string
    if err := c.ShouldBindJSON(&status); err != nil {
        c.JSON(503, gin.H{"status": "failed"})
    }
    c.JSON(200, gin.H{"status": "OK"})
}

the handler function is returning error messages depending what it is supposed to do, given that I have lots of functions with duplicate error handling code to produce error response.

How to I wrap this handler to externalise the error handling and response formatting. E.g.:

package main

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

func main() {
    r := gin.Default()
    r.POST("/status", wrapper(handler_status))
    r.GET("/health", wrapper(handler_health))
    r.Run(":8080")
}

func wrapper(f func(c *gin.Context) (string, error)) gin.HandlerFunc {

    status, err := f()

    if err != nil {
        c.JSON(503, gin.H{"status": err})
        return
    }
    c.JSON(200, gin.H{"status": "OK"})
}

func handler_status(c *gin.Context) (string, error) {

    var status string
    if err := c.ShouldBindJSON(&status); err != nil {
        return "failed", err
    }
    return status, nil
}

func handler_health(c *gin.Context) (string, error) {

    return "roger", nil
}

But I don't have access to *gin.Context in wrapper() ... what is the best way to solve this?

Erik
  • 163
  • 1
  • 2
  • 10
  • In your `wrapper` you forgot to actually return the `HandlerFunc`. Something like this: https://play.golang.org/p/IkE9i3OaYnx – mkopriva Sep 19 '20 at 12:04
  • The whole concept is known as a middleware. You can put multiple handler functions in the route, so for example `r.GET("/myEndpoint", middleware1, middleware2, handler)` and inside middleware1 and middleware2 you can do `c.Next()` to 'freeze' in current middleware and jump to next one and so one. You can read more here https://github.com/gin-gonic/gin#using-middleware – Vrangz Sep 22 '20 at 12:52

1 Answers1

6

Thanks your suggestion, that helped :-) The correct wrapper function is:

func wrapper(f func(c *gin.Context) (string, error)) gin.HandlerFunc {

    return func(c *gin.Context) {
        _, err := f(c)
        if err != nil {
            c.JSON(503, gin.H{"status": err})
            return
        }
        c.JSON(200, gin.H{"status": "OK"})
    }
}
Erik
  • 163
  • 1
  • 2
  • 10
  • You might like the approach here https://stackoverflow.com/questions/48224908/better-error-handling – keni Jun 26 '21 at 16:05