I have a struct that i'm trying to validate a struct using validator v10 for which field can be of type null.XX from null.v4 package.
type FooStruct struct {
Foo null.Int `json:"foo" binding:"nullIntMin=1"`
}
it's (obviously ) not working out of the box so i'm trying to make a custom validator.
var validateNullIntMin validator.Func = func(fl validator.FieldLevel) bool {
number, ok := fl.Field().Interface().(null.Int)
min := cToInt(fl.Param())
if ok {
if number.Value > min && number.Valid {
return false
}
}
return true
}
func cToInt(param string) int64 {
i, err := strconv.ParseInt(param, 0, 64)
panic(err)
return i
}
The problem is that the data is never validated. Is never even entering the function and i can't understand why.
example to reproduce :
package main
import (
"log"
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator"
"gopkg.in/guregu/null.v4"
)
type FooStruct struct {
Foo null.Int `json:"foo" binding:"nullIntMin=3"`
}
var validateNullIntMin validator.Func = func(fl validator.FieldLevel) bool {
log.Println("inside validator")
number, ok := fl.Field().Interface().(null.Int)
min := cToInt(fl.Param())
if ok {
if number.Valid && number.Int64 > min {
return false
}
}
return true
}
func cToInt(param string) int64 {
i, err := strconv.ParseInt(param, 0, 64)
panic(err)
return i
}
func main() {
route := gin.Default()
// Custom validator
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
v.RegisterValidation("nullIntMin", validateNullIntMin)
}
route.POST("/foo", postFoo)
route.Run(":5000")
}
func postFoo(c *gin.Context) {
var f FooStruct
err := c.BindJSON(&f)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"status": http.StatusText(http.StatusBadRequest)})
return
}
c.JSON(http.StatusOK, gin.H{"status": http.StatusText(http.StatusOK), "data": f.Foo.Int64})
}
if you call it with
{"foo":1}
you'll get { "data": 1, "status": "OK" }
when i'm expecting Error:Field validation for 'Foo' failed on the 'nullIntMin' tag
You dont need to unparse the field inside the validator and make a custom case just for the special type.
Instead just create a new type then you can just use the normal bindings.