hapijs / joi

The most powerful data validation library for JS
Other
20.94k stars 1.51k forks source link

Using `.when` to check 2 values #3041

Open jwarby opened 5 months ago

jwarby commented 5 months ago

Runtime

Node.js

Runtime version

v20.4

Module version

17

Used with

standalone

Any other relevant information

No response

How can we help?

Hi, struggling to figure out how I can apply a then clause based on whether one key has a certain value or another key has a different value, hoping somebody could help...

I currently have something like this:

.when("foo", {
    is: "bar",
    then: object.keys({
      somethingElse: string.optional().allow()
    })
});

And I'd like to extend it so that if either foo="bar" OR baz="qux" will both apply the then. I know I could† add another .when and move my then stuff into a var, or duplicate it (actual code has a lot of conditions though so want to avoid any duplication) like this:

const overrides = object.keys({ somethingElse: string.optional().allow("") });

/* ...snip...  */
.when("foo", { is: "bar", then: overrides })
.when("baz", { is: "qux", then: overrides })

but it feels like there must be a cleaner way to do it? Maybe with alternatives or something?

Thank you :pray:

† I'm assuming this would work anyway, haven't actually tried it

Marsup commented 5 months ago

There's nothing wrong in composing schemas through variables. You can also use shared schemas. I'd need a more complete example to provide relevant advice, but if your condition is to be applied in many places, you can take it up a level if that helps, like this:

Joi.object({
  foo: Joi.string(),
  baz: Joi.string(),
  quux: Joi.boolean().required(),
}).when(
  Joi.alternatives([
    // Partial checks of the inner object
    Joi.object({ foo: Joi.valid("bar").required() }).unknown(),
    Joi.object({ baz: Joi.valid("qux").required() }).unknown(),
  ]),
  {
    // This will be merged with the base object
    then: Joi.object({ 
      somethingElse: Joi.string(),
      anotherThing: Joi.boolean(),
    }),
  }
)