Robert Walker
Robert Walker

Reputation: 171

How to check for a valid object in Joi

I have an array of objects that represent valid combinations of input to my endpoint:

const portfolios = [
  { "name": "portfolioA", "product": "productA" },
  { "name": "portfolioB", "product": "productB" },
  { "name": "portfolioB", "product": "productC" },
  { "name": "portfolioC", "product": "productD" },
  ...
]

For example, a user can request 'portfolioA' with 'productA' but not 'productB' or they can request 'portfolioB' with either 'productB' or 'productC'.

The input I'll get will look like this:

 portfolio: {
   name: "portfolioA",
   product: "productA"
 }

I'd like to be able to check this object against the valid objects in 'portfolios' programmatically. I thought this could be done using Joi.object().valid(portfolios) but the validation fails.

I can use when() to check against each of these manually using the schema below however the array of portfolios can change and I'd rather not have to change the validation code each time. I'd prefer to just give it an array of valid objects.

portfolio: {
  name: Joi.string().required(),
  product: Joi.string().required()
    .when('name', { is: Joi.string().valid('portfolioA'), then: Joi.string().valid('productA') })
    .when('name', { is: Joi.string().valid('portfolioB'), then: Joi.string().valid(['productB', 'productC']) })
}

As a side note, when validation fails I see this instead of the string representation.

 \"portfolio\" must be one of [[object Object], [object Object], [object Object], [object Object], [object Object]

Is there any way to check objects against an array of objects with Joi?

Upvotes: 0

Views: 1691

Answers (1)

Robert Walker
Robert Walker

Reputation: 171

I figured out how to do this. Joi 9.0.0-0 contains a new method called extends that solves this for me.

const portfolios = { ... }

const customJoi = Joi.extend({
  base: Joi.object(),
  name: 'portfolio',
  language: {
    isValid: `portfolio must be one of ${JSON.stringify(portfolios)}`
  },
  rules: [
    {
      name: 'isValid',
      validate(params, value, state, options) {
        const found = results.find(e => e.name === value.name && e.product === value.product);

        if (!found) {
          return this.createError('portfolio.isValid', { v: value, q: params.q }, state, options);
        }

        return found;
      }
    } 
  ]
});

Then in my validation declaration I can use

    portfolio: customJoi.portfolio().isValid().required(),

Upvotes: 4

Related Questions