I'm using Joi to validate user-submitted form data. The data contains bank details: the relevant ones here are accountNumber
and sortCode
. I need to take the value of both inputs and run them through an external API to confirm they are valid together.
I'm struggling though to write a custom Joi extension which can get the value of another field in the data. Here's a simplified version of what I've tried:
const baseJoi = require('joi');
const bankDetails = joi => {
return {
name: 'bankDetails',
base: joi.number().required(),
rules: [
{
name: 'accountNumber',
params: {
number: joi.number().required()
},
validate(params, value, state, options) {
console.log(value); // returns 12-34-46 (sortCode)
console.log(params.number); // returns a [Function: ref] object
console.log(state.parent.accountNumber); // returns 88888888, but feels "wrong"
}
}
]
};
};
const Joi = baseJoi.extend([bankDetails]);
const validateBankDetails = () => {
return Joi.bankDetails().accountNumber(Joi.ref('accountNumber')).required();
};
const schema = Joi.object({
accountNumber: Joi.number().required(),
sortCode: validateBankDetails(),
});
I know I can use Joi.ref()
inside Joi's own validators (eg. something like Joi.number().less(Joi.ref('max'))
) but here I need to take the value of that key (accountNumber
) and pass it through to another function (along with the sortCode
value). Is there a Joi-approved way of doing this? I can get the value I want from the state
parameters but this feels a bit of an anti-pattern.
Have you tried using a custom
method on a plain old Joi object instead of an extension? I think it might get you what you're looking for in a more straightforward manner:
const schema = Joi.object({
accountNumber: Joi.number().required(),
sortCode: Joi.number().required(),
})
.custom((obj, helpers) => {
// you have access to the full object above.
const { accountNumber, sortCode } = obj;
// Do your validation
const isValid = doSomething(accountNumber, sortCode);
if (!isValid) {
throw new Error('Invalid input');
}
// Just pass the object on through if things work.
return obj;
});