Как я могу проверить тип данных структуры с помощью настраиваемого валидатора?
я использую
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 неверен.
Кто-нибудь знает, что я делаю не так?
2 ответа
После долгих поисков я наконец нашел функцию под названием
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
функция и ответное сообщение будет ошибкой для
ParentStruct.Child
поле
Функция
validator.RegisterValidation(...)
регистрирует настраиваемый валидатор на уровне поля , как предполагает тип зарегистрированной функции
func(fl validator.FieldLevel) bool
.
Сами поля структуры не проверяются таким образом, а ваш настраиваемый валидатор игнорируется.
Чтобы проверить поле структуры, вы должны использовать
validate.RegisterStructValidation(myValidate, ChildStruct{})
, где функция
myValidate
относится к типу
validator.StructLevelFunc
.
Затем внутри этой функции вы можете выполнить проверку структуры, либо самого поля, либо его вложенных полей:
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