hapijs / joi

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

array().items() fails validation when items contains more than 3 items #3002

Closed rtxd closed 1 year ago

rtxd commented 1 year ago

Runtime

node.js

Runtime version

16.x

Module version

17.11.0

Last module version without issue

No response

Used with

standalone

Any other relevant information

input validation issue

What are you trying to achieve or the steps to reproduce?

I'm trying to create a schema using joi.array().items() that validates an array of 3 different types of items. The JOI schema seems to be stripping one of the members even though all members comply with the schema.

I've read the documentation and it says items() should work with one or more item types

'use strict'
const joi = require('joi')

const mockData = {
  query: {
    filters: [
      {
        member: 'member',
        operator: 'equals',
        values: [1, 2, 3]
      },
      {
        and: [
          {
            member: 'andMember',
            operator: 'equals',
            values: [1, 2, 3]
          }
        ]
      },
      {
        or: [
          {
            member: 'orMember',
            operator: 'equals',
            values: [1, 2, 3]
          }
        ]
      }
    ]
  }
}

const singleFilter = joi.object({
  member: joi.string().required(),
  operator: joi.string().required(),
  values: joi.array().min(1)
})
const andFilters = joi.object({ and: joi.array().items(singleFilter) })
const orFilters = joi.object({ or: joi.array().items(singleFilter) })

const schema = joi
  .object({
    query: joi.object({
      filters: joi.array().items(singleFilter, orFilters, andFilters) // third item here gets stripped by joi
    })
  })
  .options({
    allowUnknown: true,
    stripUnknown: true
  })

;(async () => {
  const validated = await schema.validateAsync(mockData)
  console.log('validated:', JSON.stringify(validated))
})()

What was the result you got?

andFilter was stripped from schema even though it matched

{
  "query": {
    "filters": [
      {
        "member": "member",
        "operator": "equals",
        "values": [
          1,
          2,
          3
        ]
      },
      {},
      {
        "or": [
          {
            "member": "orMember",
            "operator": "equals",
            "values": [
              1,
              2,
              3
            ]
          }
        ]
      }
    ]
  }
}

What result did you expect?

{
  "query": {
    "filters": [
      {
        "member": "member",
        "operator": "equals",
        "values": [
          1,
          2,
          3
        ]
      },
      {
        "and": [
          {
            "member": "andMember",
            "operator": "equals",
            "values": [
              1,
              2,
              3
            ]
          }
        ]
      },
      {
        "or": [
          {
            "member": "orMember",
            "operator": "equals",
            "values": [
              1,
              2,
              3
            ]
          }
        ]
      }
    ]
  }
}
Marsup commented 1 year ago

Hi,

The issue is both your andFilters and orFilters don't have a discriminatory element since neither and nor or are required, so those schemas would basically match any object, setting the arrays inside those schemas as required should fix your problem.

rtxd commented 1 year ago

@Marsup Thanks!