ozzo-validation icon indicating copy to clipboard operation
ozzo-validation copied to clipboard

Nested struct validation based on field

Open RobinVdBroeck opened this issue 5 years ago • 3 comments

I would love for it to be possible to validate a field that is deeply nested. You can find an example of what I mean at: https://play.golang.org/p/bVjDNqkVzQj

In my use case, adding a Validate() function to the nested struct is not possible. The validation of the nested struct is not always the same, and depends on some external factors.

RobinVdBroeck avatar Nov 27 '20 10:11 RobinVdBroeck

Hey, I found that I could address this with my own helper like this:

func Nested(target interface{}, fieldRules ...*validation.FieldRules) *validation.FieldRules {
	return validation.Field(target, validation.By(func(value interface{}) error {
		valueV := reflect.Indirect(reflect.ValueOf(value))
		if valueV.CanAddr() {
			addr := valueV.Addr().Interface()
			return validation.ValidateStruct(addr, fieldRules...)
		}
		return validation.ValidateStruct(target, fieldRules...)
	}))
}

To use it I can do this:

wrapper := Wrapper{
	Attr1: 6,
	FieldOne: Foo{
		FieldThree: "Test",
		FieldFour:  "",
	},
	FieldTwo: &Bar{
		FieldFive: 16,
	},
}
err := validation.ValidateStruct(&wrapper,
	validation.Field(&wrapper.Attr1, validation.Required),
	Nested(&wrapper.FieldOne,
		validation.Field(&wrapper.FieldOne.FieldThree, validation.Required),
		validation.Field(&wrapper.FieldOne.FieldFour, validation.Required),
	),
	Nested(&wrapper.FieldTwo,
		validation.Field(&wrapper.FieldTwo.FieldFive, validation.Required, validation.Max(10)),
	),
)

Here's a playground link based on your initial example: https://play.golang.org/p/oLUVw6cikws

Haven't used it much so can't guarantee it's bug free, but seems to work as intended.

ki4jnq avatar Apr 12 '21 13:04 ki4jnq

@ki4jnq to access FieldFive, you may get nil pointer panic

guiguan avatar May 10 '21 23:05 guiguan

@ki4jnq to access FieldFive, you may get nil pointer panic

You mean when doing this: &wrapper.FieldTwo.FieldFive? True, your code would have to check that manually if it's a concern.

ki4jnq avatar May 11 '21 13:05 ki4jnq