3
votes

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))
        })
2
What you mean by restoring context ? - Зелёный
well when I read context once while doing validation I can't read that data again, and I need to perform other things after that validation middleware @Зелёный - bihire boris
You can read body many times, c.ShouldBindJSON is exactly about this. Show error you have. - Зелёный
the error is after c.ShouldBindJSON if you try to access data in the context it will be empty. from this same question @Зелёный - bihire boris
Please show full error message. - Зелёный

2 Answers

5
votes

You can try this.

ByteBody, _ := ioutil.ReadAll(c.Request.Body)
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(ByteBody))

You can then use ByteBody however you want without side-effects on c.Request.Body

4
votes

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}