5

I am defining a Joi schema for an object with some fields for social profiles. The goal is to ensure that all of the fields are present and that at least one of them is a non-empty string, but to allow the others to be null.

Here is what I have so far:

const socialUrl = joi.string().min(1).alphanum().allow(null);
const schema = joi.object({
    facebook : socialUrl.required(),
    twitter  : socialUrl.required(),
    youtube  : socialUrl.required()
}).required()

This works great except that the following object is considered valid:

{
    facebook : null,
    twitter  : null,
    youtube  : null
}

Using min() and or() on the object doesn't help because the fields exist, they're just the wrong type.

It would be pretty trivial to do an extra loop myself afterwards and check for the specific case of all fields being null, but that is not ideal.

This is being used for payload validation where it would be nice to know that the client understands the full schema, hence the desire that all of the fields be present. Maybe that is not worth it. I do get the sense that I could use some verbose when() code to get the job done, but it seems like at that point I might as well just make my own loop. Hoping to be proven wrong!

Seth Holladay
  • 8,951
  • 3
  • 34
  • 43

2 Answers2

2

here is ready answer: Using Joi, require one of two fields to be non empty

joi has .alternatives() method, that has .try() method in which you could simply go through all the options In each case you must keep only one required field

const socialUrl = joi.string().min(1).alphanum().allow(null);

const schema = joi.alternatives().try(
  joi.object({
    facebook: socialUrl.required(),
    twitter: socialUrl,
    youtube: socialUrl,
  }),
  joi.object({
    facebook: socialUrl,
    twitter: socialUrl.required(),
    youtube: socialUrl,
  }),
  joi.object({
    facebook: socialUrl,
    twitter: socialUrl,
    youtube: socialUrl.required(),
  }),
);

So, you don't need to use .min() or .or()

IlnurIbat
  • 83
  • 8
  • 1
    Hi and thanks for helping. Unfortunately, this doesn't validate that all fields are present. So objects like `{ facebook : 'foo' }` validate successfully, where I want to require the input to be `{ facebook : 'foo', twitter : null, youtube : null }` instead. – Seth Holladay Oct 23 '17 at 23:10
  • @SethHolladay Could you give me at least one-three valid and invalid examples? – IlnurIbat Oct 25 '17 at 11:04
  • Sure! I made a repo with tests @IlnurIbat see https://github.com/sholladay/repro-so-45123536 – Seth Holladay Oct 31 '17 at 02:33
0

You can use oxor operator, here's a description. It worked for my case, which I was 2 fields that can't be used at the same time, but if both of them are not used I don't want to receive any warnings as if I used xor...