gogo-gin

Go-Gin read request body many times


I am trying to restore the context with it's data after performing validation on it's data.I need the data to keep moving as need it later on in the next function.

I am new to golang and the below code is as far I could go. any help and a better approach is much appreciated.

thanks in advance.

the validation middleware

func SignupValidator(c *gin.Context) {
    // Read the Body content
    // var bodyBytes []byte
    // if c.Request.Body != nil {
    //  bodyBytes, _ = ioutil.ReadAll(c.Request.Body)
    // }
    var user entity.User
    if err := c.ShouldBindJSON(&user); err != nil {
         validate := validator.New()
         if err := validate.Struct(&user); err != nil {
              c.JSON(http.StatusBadRequest, gin.H{
                 "error": err.Error(),
          })
          c.Abort()
          return
        }
        // c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
    }
    // Read the Body content
    var bodyBytes []byte
    if c.Request.Body != nil {
        bodyBytes, _ = ioutil.ReadAll(c.Request.Body)
    }
    fmt.Println(string(bodyBytes)) // this empty
    c.Next()

}

route

auth.POST("login", gin.Logger(), validations.SignupValidator, func(ctx *gin.Context) {
            ctx.JSON(200, videoController.Save(ctx))
        })

Solution

  • Here is an example of reading body twice with ShouldBindBodyWith, check it:

    package main
    
    import (
        "log"
        "net/http"
    
        "github.com/gin-gonic/gin"
        "github.com/gin-gonic/gin/binding"
    )
    
    type ParamsOne struct {
        Username string `json:"username"`
    }
    
    type ParamsTwo struct {
        Username string `json:"username"`
    }
    
    func main() {
        r := gin.New()
        r.POST("/", func(c *gin.Context) {
            var f ParamsOne
            // Read ones
            if err := c.ShouldBindBodyWith(&f, binding.JSON); err != nil {
                log.Printf("%+v", err)
            }
            log.Printf("%+v", f)
            var ff ParamsTwo
            
            if err := c.ShouldBindBodyWith(&ff, binding.JSON); err != nil {
                log.Printf("%+v", err)
            }
            log.Printf("%+v", ff)
            c.IndentedJSON(http.StatusOK, f)
        })
        r.Run(":4000")
    }
    

    Output:

    $example: ./example
    [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
     - using env:   export GIN_MODE=release
     - using code:  gin.SetMode(gin.ReleaseMode)
    
    [GIN-debug] POST   /                         --> main.main.func1 (1 handlers)
    [GIN-debug] Listening and serving HTTP on :4000
    2020/07/05 10:47:03 {Username:somename}
    2020/07/05 10:47:03 {Username:somename}