validationgogo-playground

Golang create custom validator that executes method of an interface


I am trying to create my own validator for gin, but I want it to be "generic", so let's say, I want to have an interface IsValid

type IsValid interface {
    IsValid() bool
}

, and make some structs to have binding:"IsValid" in some fields that implement that interface.

But I don't know how to write my custom validator to get the field, cast it to the IsValid interface, and then execute the isValid method.

I am using the go-playground validator package: https://github.com/go-playground/validator

if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
    // registering validation for isValid
    v.RegisterValidation("isValid", func(fl validator.FieldLevel) bool {
        isValidField := // TODO do something to cast it to that interface
        return isValidField.IsValid()
    })
}

Solution

  • The FieldLevel type has this method:

    // returns current field for validation
    Field() reflect.Value
    

    reflect.Value has this method:

    func (v Value) Interface() (i any)
    

    Interface returns v's current value as an interface{}. It is equivalent to:

    var i interface{} = (v's underlying value)

    It panics if the Value was obtained by accessing unexported struct fields.

    You can use a type assertion to utilize an interface{} / any value as a more specific interface like this:

    var i interface{} = something
    var x = i.(MyInterface)
    

    This will panic if the value i doesn't implement MyInterface. To check for that case, the alternate form can be used:

    var x, ok = i.(MyInterface)
    if ok {
        // use x
    } else {
        // type conversion failed
    }
    

    Putting it together, your code would be something like this:

    isValidField, ok := fl.Field().Interface().(IsValid)