go-playground / validator

:100:Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving
MIT License
16.64k stars 1.32k forks source link

How can I skip validation for the nil values (require ONLY for non-nil values)? #1186

Closed tarampampam closed 11 months ago

tarampampam commented 11 months ago

Package version eg. v9, v10:

v10

Issue, Question or Enhancement:

How can I skip the validation for the structure fields only if they are nil? Perhaps you can advise me on how to implement a custom tag like omitnil?

Code sample to showcase or reproduce:

func TestValidation(t *testing.T) {
    type s struct {
        Str    string  `validate:"omitempty,required,min=10"`
        StrPtr *string `validate:"omitempty,required,min=10"`
    }

    // I'm expecting an error here because "Str" is not nil, but validation
    // passed without an error
    if err := New(WithRequiredStructEnabled()).Struct(s{}); err == nil {
        t.Fatal("no error")
    }
}

If I do the following:

type s struct {
    Str    string  `validate:"required,min=10"`
    StrPtr *string `validate:"omitempty,min=10"`
}

Everything works as expected, but since structures with validation rules are generated from the OpenAPI specification, I need to skip the validation only for the nil values.

tarampampam commented 11 months ago

Maybe, is there any way to override the omitempty behavior? I mean to skip the validation only if the struct field is a pointer.

deankarn commented 11 months ago

Try using a custom validator in combination with the or syntax eg. is_pointer|othervalidations

tarampampam commented 11 months ago

Yea, I have tried:

validate.RegisterValidation("is_pointer", func(fl validator.FieldLevel) bool {
    return fl.Field().Kind() == reflect.Ptr
})

type s struct {
    Foo string  `validate:"is_pointer|min=10"`
    Bar *string `validate:"is_pointer|min=10"`
}

But without success 😞

tarampampam commented 11 months ago

@deankarn I made a PR with a new modifier, and hope you will approve. Feel free to ask for more details if needed!

deankarn commented 11 months ago

☝️ maybe I’m missing something.

Why can’t you use the working example in original comment? Adding a new modifier requires you to change the tags also, or is it some sort of all or nothing thing?

tarampampam commented 11 months ago

Because omitempty will skip the validation even if the value is empty ("" for strings, 0 for (u)int, false for bool, and so on), but omitnil will skip only if the value is nil. This is the main point.

tarampampam commented 11 months ago

Plus, since the context of this issue arises from code generation from the OpenAPI spec, it has the following rule: you should not validate the value only if it has a pointer type and equals to nil. After the PR is merged, I can assign the rule omitnil,required,... to every struct field and be sure that if a value is provided, it will be validated correctly. Otherwise, if it is nil, the validation will be skipped because nil means "not required and should be ignored." The cherry on top is that for both cases, I will only need to use one rule, without the headache of deciding whether to define required or omitempty here.

deankarn commented 11 months ago

Because omitempty will skip the validation even if the value is empty ("" for strings, 0 for (u)int, false for bool, and so on), but omitnil will skip only if the value is nil. This is the main point.

I am aware of how omitempty works.

My question is why can’t you use required in place of omitempty just like your working example for non pointer values as that’s the behaviour you want.

deankarn commented 11 months ago

TY for the extra context, it makes more sense now.

let me thing on it a bit, adding new modifiers needs to be thought through carefully and how they may interact with all the existing ones. It may take a while as my time is tied up in another project ATM but will try to get to it soon.

tarampampam commented 11 months ago

@deankarn Do you have any update? 😃

Update: I have tested the changes from the PR locally - all works like a charm!

nodivbyzero commented 11 months ago

This PR fixes validation omitempty for empty String pointer: https://github.com/go-playground/validator/pull/1173

tarampampam commented 11 months ago

And fixes #1129

tarampampam commented 11 months ago

Friendly ping @deankarn

arobert93 commented 4 months ago

Any updates? @deankarn