Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I run a custom validation against a different key in my schema?

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.

like image 958
Matt Andrews Avatar asked Oct 17 '25 09:10

Matt Andrews


1 Answers

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;
  });
like image 176
Mark McKelvy Avatar answered Oct 18 '25 23:10

Mark McKelvy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!