Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to Enable BindValidation after it is diabled using gin.DisableBindValidation #2818

Open
NishantG01 opened this issue Aug 12, 2021 · 4 comments

Comments

@NishantG01
Copy link

NishantG01 commented Aug 12, 2021

Description

I want to limit the impact of gin.DisableBindValidation within a function and should be able to re-enable it.
Currently, I have many routes, all the routes need the gin validation and few routes need to consume the incoming request modify the data and then do the validation again

IF I use gin.DisableBindValidation, all the other routes get impacted.

How to reproduce

  1. gin.DisableBindValidation
  2. add some required field
  3. send the request for route /api/v1/get - this works as it is but
  4. the other registered routes which require field validation, don't work
package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"reflect"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/validator/v10"
)

type User struct {
	Email string `json:"email" form:"e-mail" binding:"required"`
	Name  string `json:"name" binding:"required"`
        Org string `json:"org" binding:required"`
}

func main() {
	route := gin.Default()
	route.POST("/user", validateUser)
        route.GET("/validate",validateUsers)
	route.Run(":8085")
}

func validateUser(c *gin.Context) {
	var u User
	if err := c.ShouldBindJSON(&u); err == nil {
		c.JSON(http.StatusOK, gin.H{"message": "User validation successful."})
	} else {
		c.JSON(http.StatusBadRequest, gin.H{"errors": err.Error()})
		return
	}
}
func validateUsers(c *gin.Context) {
	var u []User
        gin.DisableBindValidation().  
//Note: As soon as this route gets executed the validateUser route will stop validating the json
	if err := c.ShouldBindJSON(&u); err == nil {
		c.JSON(http.StatusOK, gin.H{"message": "User validation successful."})
	} else {
		c.JSON(http.StatusBadRequest, gin.H{"errors": MarshalErr(*jsErr)})
		return
	}
        for _,user:=range u{
                 u.Org="asb"
        }
        //enable bind validation
       //revalidate the struct array
}

Expectations

The data is validated for array request after adding the missing required field as well as with single request

Actual result

The /users requests start failing once gin.DisableBindValidation is called.

Environment

  • go version:
  • gin version (or commit ref):
  • operating system:
@jimbirthday
Copy link

jimbirthday commented Aug 13, 2021

@NishantG01
I found a function under the test unit

github.com/gin-gonic/gin@v1.7.3/binding/binding_test.go

image

I refer to the writing of this unit test


import (
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"net/http"
)

type User struct {
	Email string `json:"email" form:"e-mail" binding:"required"`
	Name  string `json:"name" binding:"required"`
	Org   string `json:"org" binding:"required"`
}

func main() {
	route := gin.Default()
	route.POST("/user", validateUser)
	route.GET("/validate", validateUsers)
	route.Run(":8085")
}

func validateUser(c *gin.Context) {
	var u User
	if err := c.ShouldBindJSON(&u); err == nil {
		c.JSON(http.StatusOK, gin.H{"message": "User validation successful."})
	} else {
		c.JSON(http.StatusBadRequest, gin.H{"errors": err.Error()})
		return
	}
}
func validateUsers(c *gin.Context) {
	var u []User
	backup := binding.Validator
	defer func() {binding.Validator = backup}()
	gin.DisableBindValidation()
	//Note: As soon as this route gets executed the validateUser route will stop validating the json
	if err := c.ShouldBindJSON(&u); err == nil {
		c.JSON(http.StatusOK, gin.H{"message": "User validation successful."})
	} else {
		c.JSON(http.StatusBadRequest, gin.H{"errors":err.Error()})
		return
	}
}

  1. /validate

image

  1. /user

image

I hope this is the result you want

@NishantG01
Copy link
Author

@jimbirthday,

Thanks for your response. Appreciate it.
The issue with this approach is that the concurrent calls will pass through as soon as the gin.DisableBindValidation() is executed.
Meaning if any request comes for /user, while /validate executed gin.DisableBindValidation,
func validateUser will not check for Binding validation.

@jimbirthday
Copy link

@NishantG01

Then you may be able to use a custom tag verification method to prevent a special tag from being validated.

Something like this:

	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		v.RegisterValidation("bookabledate", bookableDate)
	}

@jimbirthday
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants