Joi: Validation of field based on inclusion in objects in an array.

Created on 3 May 2020  路  2Comments  路  Source: sideway/joi

Support plan

  • which support plan is this issue covered by? (e.g. Community, Core, Plus, or Enterprise): Community
  • is this issue currently blocking your project? (yes/no): no
  • is this issue affecting a production system? (yes/no): no

Context

  • node version: 14
  • module version: 17.1.1
  • environment (e.g. node, browser, native): node
  • used with (e.g. hapi application, another framework, standalone, ...): standalone
  • any other relevant information:

What problem are you trying to solve?


I am trying to use Joi.ref() to point to a path which would resolve the key of an array of objects. The use case im trying to support is to verify that an id reference exists within the document.

The data im trying to validate looks as such:

const data = {
  rootNodeId: '5eaf1d153440b9a81c3baec3',
  nodes: [
    {
      id: '5eaf1d153440b9a81c3baeae',
      nodeType: 'WAIT',
      metadata: {
        value: 5,
        unit: 'DAYS',
      },
    },
    {
      id: '5eaf1d153440b9a81c3baeb1',
      nodeType: 'COUNT',
      metadata: 5,
    },
    {
      id: '5eaf1d153440b9a81c3baec3',
      nodeType: 'TASK',
      metadata: null,
    }
  ]
}

Im looking for a way to validate that the value of rootNodeId exists as an id inside the array nodes. I've tried using Joi.ref('nodes.id', { in: true, iterables: true }) in order to point to these ids, however i get validation errors for valid schemas.

The full schema im using is:

const schema = Joi.object().keys({
  rootNodeId: Joi.valid(Joi.ref('nodes.id', { in: true, iterables: true })),
  nodes: Joi.array().items(Joi.object().keys({
    id: Joi.string().hex().length(24).required(),
    nodeType: Joi.string().valid(...constants.NODE_TYPES).required(),
    metadata: Joi.any().required(),
  })),
});

Apart from just trying Joi.ref('nodes.id', { in: true, iterables: true }), I've also tried the following:

Joi.ref('nodes[].id', { in: true, iterables: true })
Joi.ref('nodes[.id]', { in: true, iterables: true })
Joi.ref('nodes[id]', { in: true, iterables: true })
Joi.ref('nodes[].id', { in: true, iterables: false })

Do you have a new or modified API suggestion to solve the problem?

The solution would involve giving references some syntax to reference into arrays or objects. I think a possible solution could be taken from the jq command-line tool, in the way that it resolves nested values.

feature

Most helpful comment

@sfinnman Not a complete solution, but would something like this work? (Haven't tried it myself)

const nodesRef = Joi.ref('nodes', {
  in: true,
  adjust: (nodes) => nodes.map(node => node.id)
});

const schema = Joi.object().keys({
  rootNodeId: Joi.any().valid(nodesRef),
  nodes: Joi.array().items(Joi.object().keys({
    id: Joi.string().hex().length(24).required(),
    nodeType: Joi.string().valid(...constants.NODE_TYPES).required(),
    metadata: Joi.any().required(),
  })),
});

All 2 comments

@sfinnman Not a complete solution, but would something like this work? (Haven't tried it myself)

const nodesRef = Joi.ref('nodes', {
  in: true,
  adjust: (nodes) => nodes.map(node => node.id)
});

const schema = Joi.object().keys({
  rootNodeId: Joi.any().valid(nodesRef),
  nodes: Joi.array().items(Joi.object().keys({
    id: Joi.string().hex().length(24).required(),
    nodeType: Joi.string().valid(...constants.NODE_TYPES).required(),
    metadata: Joi.any().required(),
  })),
});

Your solution seems to work. Another one would be:

const schema = Joi.object().keys({
    rootNodeId: Joi.any(),
    nodes: Joi.array().items(Joi.object().keys({
        id: Joi.string().hex().length(24).required(),
        nodeType: Joi.string().valid(...constants.NODE_TYPES).required(),
        metadata: Joi.any().required(),
    })).has(Joi.object({ id: Joi.link('....rootNodeId') }).unknown()),
});

I'm not sure which one is preferred so pick the one your understand the most.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ashrafkm picture ashrafkm  路  3Comments

PaunPrashant picture PaunPrashant  路  3Comments

JbIPS picture JbIPS  路  4Comments

REBELinBLUE picture REBELinBLUE  路  3Comments

kevbook picture kevbook  路  4Comments