Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

required_without doesn't seem to work with multiple fields #617

Open
fizzy123 opened this issue May 29, 2020 · 14 comments · May be fixed by #1324
Open

required_without doesn't seem to work with multiple fields #617

fizzy123 opened this issue May 29, 2020 · 14 comments · May be fixed by #1324

Comments

@fizzy123
Copy link

fizzy123 commented May 29, 2020

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

@deankarn
Copy link
Contributor

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 :)

@ozburo
Copy link

ozburo commented Aug 12, 2020

I just got bit w/ this too 😃

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?

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

Cheers 👍

@andig
Copy link

andig commented Sep 28, 2020

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.

@yaliv
Copy link

yaliv commented Sep 29, 2020

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 ☹️

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

required_without=Field1,required_without=Field2

@andig
Copy link

andig commented Sep 29, 2020

@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.

@yaliv
Copy link

yaliv commented Sep 29, 2020

@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"

@yaliv
Copy link

yaliv commented Sep 29, 2020

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 👍
"without = any empty" --> it doesn't work 👎

@yaliv
Copy link

yaliv commented Sep 29, 2020

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

@andig
Copy link

andig commented Oct 1, 2020

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‘ll 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.

@yaliv
Copy link

yaliv commented Oct 1, 2020

@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.

@yaliv
Copy link

yaliv commented Oct 1, 2020

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 😉

@andig
Copy link

andig commented Oct 1, 2020

@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?

@yaliv
Copy link

yaliv commented Oct 1, 2020

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 ✔️

@galperets
Copy link

Hi,

Just checking if this was fixed already, or planned to be fixed?
Here is another simple example that fails:
type MyStruct struct {
Field1 *a validate:"required_without=Field3 Field2"
Field2 *b
Field3 *b
}

type a struct {
Aa string
}

type b struct {
Bb string
}

https://go.dev/play/p/kOF6ROYXlw1

Will be happy if this would be solved.

Thanks.

jmfrees added a commit to jmfrees/validator that referenced this issue Oct 3, 2024
@jmfrees jmfrees linked a pull request Oct 3, 2024 that will close this issue
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants