Search code examples
node.jsjoi

Difficult to understand what exactly .has does with array in joi


I was trying to learn JOI to validate a schema,I came across the following content

const schema = Joi.array().items(
  Joi.object({
    a: Joi.string(),
    b: Joi.number()
  })
).has(Joi.object({ a: Joi.string().valid('a'), b: Joi.number() }))

And I validated the scheme as follow let c = arr2.validate([{ a:'a', b:'b'}]) the response I got on validation is

{
  value: [ { a: 'a', b: 'b' } ],
  error: [Error [ValidationError]: "[0].b" must be a number] {
    _original: [ [Object] ],
    details: [ [Object] ]
  }
}

then I tried the above validation with the schema as follows

const arr2 = Joi.array().items(
  Joi.object({
    a: Joi.string(),
    b: Joi.number()
  })
)

even now I got the following validation response

{
  value: [ { a: 'a', b: 'b' } ],
  error: [Error [ValidationError]: "[0].b" must be a number] {
    _original: [ [Object] ],
    details: [ [Object] ]
  }
}

I'm just confused as to whats the use of .has in the first schema as I can have the valid value directly as below

const arr2 = Joi.array().items(
  Joi.object({
    a: Joi.string().valid('a'),
    b: Joi.number()
  })
)

then what exact purpose is .has serving in the first schema


Solution

  • As stated in the .has() documentation:

    Verifies that a schema validates at least one of the values in the array

    The example schema...

    const schema = Joi.array().items(
      Joi.object({
        a: Joi.string(),
        b: Joi.number()
      })
    ).has(Joi.object({ a: Joi.string().valid('a'), b: Joi.number() }))
    

    ...requires at least one of the array items to pass the validation { a: Joi.string().valid('a'), b: Joi.number() }

    e.g.

    { "a": "a", "b": 12345 }
    

    Your schema on the other hand...

    const arr2 = Joi.array().items(
      Joi.object({
        a: Joi.string().valid('a'),
        b: Joi.number()
      })
    )
    

    ...will only accept items that pass the validation { a: Joi.string().valid('a'), b: Joi.number() }.

    The first schema will still accept something like...

    [
        {
            "a": "foo",
            "b": 12
        },
        {
            "a": "a",
            "b": 99
        },
        {
            "a": "bar",
            "b": 6
        }
    ]
    

    ...where yours will not because not all a keys have the value 'a'.