如何使用自定义验证器验证结构数据类型?
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")
}
搜索了一段时间后,我终于找到了一个名为 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
字段的错误
我正在使用 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")
}
搜索了一段时间后,我终于找到了一个名为 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
字段的错误