I'm trying to validate a struct which has two fields, one of them is required and the other one is not.
This is the struct:
type man struct {
// required: true
Numbers []int `json:"numbers"`
// required: false
Pass bool `json:"pass"`
}
In order to validate I'm using this package: https://pkg.go.dev/gopkg.in/validator.v2
My goal is to create the below condition:
Numbers is nonzero OR pass is true.
However, if I define numbers as nonzero it will block the check of the Pass field.
I've tried to create a customized validator function, but since one of the fields is not required, I'm not sure how to build this conditions.
Thanks!
CodePudding user response:
With more recent versions of the validator package (e.g. v9
onward) you can use required_without
tag.
The field under validation must be present and not empty only when any of the other specified fields are not present. For strings ensures value is not "". For slices, maps, pointers, interfaces, channels and functions ensures the value is not nil.
type man struct {
Numbers []int `json:"numbers" validate:"required_without=Pass"`
Pass bool `json:"pass"`
}
Testing with different inputs:
man{}
man{nil, false}
man{nil, true}
man{[]int{}, false}
Gives:
Key: 'man.Numbers' Error:Field validation for 'Numbers' failed on the 'required_without' tag
Key: 'man.Numbers' Error:Field validation for 'Numbers' failed on the 'required_without' tag
pass
pass
Unfortunately with v2
you can only implement single field validation, so you don't really have a nice and straightforward way to access the parent struct. You might have to wrap the struct in another struct to consider man
as a field.
type wrapper struct {
man man `validate:"man"`
}
// Very simple validation func
func manValidator(v interface{}, param string) error {
m := v.(man)
if m.Numbers != nil || m.Pass {
return nil
}
return errors.New("validation failed")
}
func main() {
validate.SetValidationFunc("man", manValidator)
validator.Validate(wrapper{man{}})
}
CodePudding user response:
type Man struct {
// required: true
Numbers []int `json:"numbers" cond1:"nonnil"`
// required: false
Pass bool `json:"pass" cond2:"nonzero"`
}
func main() {
// ....
cond1Validator := validator.NewValidator()
cond1Validator.SetTag("cond1")
cond2Validator := validator.NewValidator()
cond2Validator.SetTag("cond2")
if errs := cond1Validator.Validate(man); errs != nil {
if errs := cond2Validator.Validate(man); errs != nil {
log.Fatalln(errs)
}
}
// ....
}
You can try custom tag name and multiple vaidators..