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 })
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.
@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.
Most helpful comment
@sfinnman Not a complete solution, but would something like this work? (Haven't tried it myself)