Как я могу проверить тип данных структуры с помощью настраиваемого валидатора?

я использую 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

Другие вопросы по тегам