Search code examples
gogo-gin

Go Gin : Creating generic custom validators


I am using go Gin to create APIs in my project. I have requirement to create custom validators so I created like:

var valueone validator.Func = func(fl validator.FieldLevel) bool {
    value, ok := fl.Field()
    if ok {
        if value != "one" {
                  return true
                }
    }
    return true
}

var valuetwo validator.Func = func(fl validator.FieldLevel) bool {
    value, ok := fl.Field()
    if ok {
        if value != "two" {
                  return true
                }
    }
    return true
}
....

Instead of creating almost same custom validator multiple times, is there a way to create a single validator which is more generic and can be used for both cases, something like:

var value validator.Func = func(fl validator.FieldLevel, param) bool {
    value, ok := fl.Field()
    if ok {
        if value != param {
                  return true
                }
    }
    return true
}

I am not able to find a way to pass parameter to custom validator in gin or to make these generic validators through any other possible way. I have requirement to create like thousands of almost similar validator and I don't want to create custom validator for each one of them.


Solution

  • You can't change the function structure, as this is how it defined within the package.

    // Func accepts a FieldLevel interface for all validation needs. The return
    // value should be true when validation succeeds.
    
    type Func func(fl FieldLevel) bool
    

    instead, we could try custom validation tag with a parameter

    see the sample below

    package main
    
    import (
        "github.com/go-playground/validator"
    )
    
    type Data struct {
        One string `json:"one" validate:"custom_validation=one"`
        Two string `json:"two" validate:"custom_validation=two"`
    }
    
    var validate *validator.Validate
    
    func main() {
        validate = validator.New()
    
        err := validate.RegisterValidation("custom_validation", func(fl validator.FieldLevel) bool {
            value := fl.Field()
            param := fl.Param()
    
            return value.String() == param
        })
    
        if err != nil {
            panic(err)
        }
    
        // this will succeed
        {
            data := &Data{
                One: "one",
                Two: "two",
            }
    
            err = validate.Struct(data)
            if err != nil {
                panic(err)
            }
        }
    
        // it will fail here
        {
            data := &Data{
                Two: "one",
                One: "two",
            }
    
            err = validate.Struct(data)
            if err != nil {
                panic(err)
            }
        }
    }
    

    See more examples at here

    Note : Golang doesn't support !==