Validator: required_without doesn't seem to work with multiple fields

Created on 29 May 2020  路  13Comments  路  Source: go-playground/validator

Package version eg. v8, v9:

Package version v9

Issue, Question or Enhancement:

In this example, I would expect validation to succeed, but it doesn't despite all the required_without fields being present.

Code sample, to showcase or reproduce:

https://play.golang.org/p/O9CuEA2aOFr

enhancement question

All 13 comments

Hey @fizzy123 this will work if you use required_without_all it looks like some of the docs have been copy-pasted and are not 100% correct.

I could use some help with that if you have some time :)

I just got bit w/ this too :smiley:

help with docs

So, am I right in thinking that required_without_all is the plural/list version of required_without, i.e. If you want to have a list of Fields to check against you must use the "_all" version?

It looks that way from my tests but thought I'd ask before I go too deep into the rabbit hole.

Also, are these the docs you refer too?
https://github.com/go-playground/validator/blob/0ab8e0351d0126a6c1325b8df8cd4fa06a13e229/doc.go#L293

Cheers 馃憤

I'm having the same problem:

type Settings struct {
    Opt, Val string
}

cc := struct {
    Model    string
    Value    string
    Settings *Settings `validate:"required_without_all=Model Value"`
}{
    Model: "foo",
    // Value: "bar",
}

validate := validator.New()
err := validate.Struct(cc)
fmt.Println(err)

This should imho error but doesn't. My expectation for string was

  • must exist (in case of pointer to string)
  • must not be empty ("")

Could you kindly clarify what the expected required behaviour depending on type is?

I'd be happy in contributing to the docs (or making doc.go more visible), but I'm still struggling with how it's supposed to work.

See examples from the docs:

// require the field if the Field1 is not present:
Usage: required_without=Field1

// require the field if the Field1 or Field2 is not present:
Usage: required_without=Field1 Field2

Yes it says "or".
I've tried that multiple fields value, same as @fizzy123, but it doesn't work :frowning_face:

To achieve that "or" validation, here's what I do:

required_without=Field1,required_without=Field2

@yaliv reading the play from @fizzy123 the requirement is for validation to fail when _all_ fields are empty. Your suggestion is the same as the play and imho works when _any_ of the fields are empty. The way to go is required_without_all as @deankarn wrote. Unfortunately it seems as if required_without_all doesn't fully work as expected.

@andig I don't think so.

@fizzy123 wrote in the playground:

  • Field1 validate:"required_without=Field2 Field3 Field4"
  • Then he filled out Field2, Field3, Field4.

So the expected result is:
If Field2 or Field3 or Field4 is not present, then Field1 is required. He filled out all those 3 fields, so Field1 is not required.
But it's not:
"Field1 is still required"

Now let's compare it with required_without_all.
See example from the docs:

// require the field if the Field1 and Field2 is not present:
Usage: required_without_all=Field1 Field2

If we modify the validation above:

  • Field1 validate:"required_without_all=Field2 Field3 Field4"

The expected result is:
If Field2 and Field3 and Field4 are not present, then Field1 is required.
Meaning that all those 3 fields have to be empty for Field1 to be required.

If any of those 3 fields has value, then Field1 is not required.

I've tried both scenarios.
"without all = all empty" --> it works :+1:
"without = any empty" --> it doesn't work :-1:

Indeed, some of the docs are not 100% correct.
And we can see what's actually done by those 2 validators:
https://github.com/go-playground/validator/blob/v9.31.0/baked_in.go#L1384-L1403

But I hope this library has 3 types of required validation:

  • without = one field empty
  • without_all = all fields empty
  • without_any = any field empty

As I said before, the current workaround for without_any ("or" validation) is like this one:

required_without=Field1,required_without=Field2

In the play, fields 2..4 are populated. Field 1 should never throw a validation error regardless if without or without_all is used, yet it does. If you see my issue above you鈥榣l see another problem with the logic- also without_all seems to error (or rather _not_ error) when it should. Imho there is something wrong with the without* validations.

@andig let's try both validators right in the playground:

  • Field1 validate:"required_without=Field2 Field3 Field4" --> result: Key: 'a.Field1' Error:Field validation for 'Field1' failed on the 'required_without' tag
  • Field1 validate:"required_without_all=Field2 Field3 Field4" --> result: Test B OK

Furthermore, let's stay with the required_without_all validator and modify the struct value:

  • a{Field2: testInt} --> result: Test B OK
  • a{} --> result: Key: 'a.Field1' Error:Field validation for 'Field1' failed on the 'required_without_all' tag

That's because required_without_all only triggers error when all mentioned fields are empty.

Now let's talk about your example code.

If you don't fill any fields like this:

cc := struct {
    Model    string
    Value    string
    Settings *Settings `validate:"required_without_all=Model Value"`
}{}

you'll get an error: Key: 'Settings' Error:Field validation for 'Settings' failed on the 'required_without_all' tag

Field Settings is required when all mentioned fields are empty. Same as my explanation above.
If you fill Model, then Settings is not required.
If you fill Value, then Settings is not required too.
There's nothing wrong with this validator :wink:

@yaliv you are right. Thank you for correcting my mistake. I really appreciate your feedback.

There is still something wrong with require_without, please see https://play.golang.org/p/ljheF_I2uwN:

s := struct {
    Field1 string `validate:"required_without=Field2"`
    Field2 string `validate:"required_without=Field1"`
}{
    Field1: "Field1",
}

This _should_ error on Field1 but doesn't?

s := struct {
  Field1 string `validate:"required_without=Field2"`
  Field2 string `validate:"required_without=Field1"`
}{
  Field1: "Field1",
}

This _should_ error on Field1 but doesn't?

Nope, that's fine.

I do the same. See mine:

type Auth struct {
    APIKey   string `json:"apiKey" validate:"required_without=Username,required_without=Password"`
    Username string `json:"username" validate:"required_without=APIKey"`
    Password string `json:"password" validate:"required_without=APIKey"`
}

From the data flow perspective, I actually don't need any validations here, because:

  • None of the fields is "always" required.
  • The next step, I still need to make sure that APIKey has value before using it, otherwise I'll be using Username and Password.

But there are still advantages of setting validations here:

  • Assume that there's no guarantee that the checking will be done in the next step. Here is the best place to set validations.
  • The error message will be uniform with any other validations.

As you can see above, it's currently the best way I can write the validations.
If Username or Password is empty, I'll get an error. But before that happen, I fill out APIKey and it's fine, validation passed :heavy_check_mark:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

donileo picture donileo  路  3Comments

phenrigomes picture phenrigomes  路  5Comments

Jake-Convictional picture Jake-Convictional  路  4Comments

dkostenko picture dkostenko  路  5Comments

anam-digicom picture anam-digicom  路  4Comments