如何使用自定义验证器验证结构数据类型?

How can I validate a struct datatype with a custom validator?

我正在使用 go-playground/validator/v10 来验证一些输入,但在使用自定义验证标签和函数时遇到了一些问题。问题是当其中一个结构字段是不同的结构时,不会调用该函数。这是一个例子:

type ChildStruct struct {
    Value int
}

type ParentStruct struct {
    Child ChildStruct `validate:"myValidate"`
}

func myValidate(fl validator.FieldLevel) bool {
    fmt.Println("INSIDE MY VALIDATOR") // <- This is never printed
    return false
}

func main() {
    validator := validator.New()
    validator.RegisterValidation("myValidate", myValidate)
    data := &ParentStruct{
        Child: ChildStruct{
            Value: 10,
        },
    }
    validateErr := validator.Struct(data)
    if validateErr != nil { // <- This is always nil since MyValidate is never called
        fmt.Println("GOT ERROR")
        fmt.Println(validateErr)
    }
    fmt.Println("DONE")
}

如果我将 parentStruct 更改为:

type ParentStruct struct {
    Child int `validate:"myValidate"`
}

一切正常。 如果我将 validate:"myValidate" 部分添加到 ChildStruct 它也可以工作,但是,返回的错误是说 ChildStruct.Value 是错误的,而它应该说 ParentStruct.Child 是错误的.

有人知道我做错了什么吗?

函数 validator.RegisterValidation(...) 正在注册一个 字段 级别的自定义验证器,因为已注册函数的类型表明 func(fl validator.FieldLevel) bool.

结构字段本身不会以这种方式验证,您的自定义验证器将被忽略。

要验证结构字段,您应该使用 validate.RegisterStructValidation(myValidate, ChildStruct{}),其中函数 myValidate 的类型为 validator.StructLevelFunc.

在此函数中,您可以执行结构验证,字段本身 and/or 其嵌套字段:

func myValidate(sl validator.StructLevel) {
    fmt.Println("INSIDE MY VALIDATOR") // now called
    if sl.Current().Interface().(ChildStruct).Value != 20 {
        sl.ReportError(sl.Current().Interface(), "ChildStruct", "", "", "")
    }
}

func main() {
    vald := validator.New()
    vald.RegisterStructValidation(myValidate, ChildStruct{})
    data := &ParentStruct{
        Child: ChildStruct{
            Value: 10,
        },
    }
    validateErr := vald.Struct(data)
    if validateErr != nil {         
        fmt.Println("GOT ERROR")
        fmt.Println(validateErr)
    }
    fmt.Println("DONE")
}

操场上的例子:https://play.golang.org/p/f0f2YE_e1VL

搜索了一段时间后,我终于找到了一个名为 RegisterCustomTypeFunc 的函数,它注册了一个自定义类型,可以让 go-playground/validator/v10 对其进行验证。所以解决方法是在问题中的例子中加入如下内容:

func childStructCustomTypeFunc(field reflect.Value) interface{} {   
    if value, ok := field.Interface().(ChildStruct); ok {
        return value.Value
    }
    return nil
}

连同:

validator.RegisterCustomTypeFunc(childStructCustomTypeFunc, ChildStruct{})

现在验证器将进入 myValidate 函数并且 return 消息将是 ParentStruct.Child 字段的错误