node.jstestingjoi

Joi Validation with two empty arrays


I am trying to use the Joi Library to prevent two arrays to be empty or null. Either of them can be null or empty but both cannot. In my research I found ways to prevent two empty strings but not arrays. I tried a couple of variations of using when but have not found a simple solution. In each case I end up in a circular dependency. The dependency issue makes sense but I am not sure how to make the library work for this case. Here is an example of my latest attempt to make this work.

Joi.object({
    addUsers: Joi.array().items(Joi.string().email()),
    removeUsers: Joi.array().items(Joi.string().email())
}).keys({
    addUsers: Joi.array().min(0).when(Joi.ref('removeUsers').length(), {
        is: 0,
        then: Joi.array().min(1)
    }),
    removeUsers: Joi.array().min(0).when(Joi.ref('addUsers').length(), {
        is: 0,
        then: Joi.array().min(1)
    })
}).xor('addUsers', 'removeUsers')
            .message('Both or Either addUsers or removeUsers must have an array of email addresses. Both cannot be empty')

This creates the following circular dependency error

"item added into group removeUsers created a dependencies error","stack":"Error: item added into group removeUsers created a dependencies error"

Any assistance is appreciated


Solution

  • After much testing and experimentation, I was able to get it to work with the following solution

    Joi.object({ 
                addUsers: Joi.when('removeUsers', {
                    is: Joi.array().length(0),
                    then: Joi.array()
                        .items(Joi.string().email())
                        .unique()
                        .required()
                        .min(1)
                        .messages({
                            'array.unique':
                                'addUsers or removeUsers must contain a unique list of emails',
                            'array.min':
                                'addUsers or removeUsers must contain at least 1 email',
                            'any.required':
                                'addUsers or removeUsers must contain at least 1 email'
                        })
                        .example(['some.user@email.com', 'non.user@email.com']),
                    otherwise: Joi.array()
                        .items(
                            Joi.string()
                                .email()
                                .custom((value, helper) => {
    
                                    const testArray = helper.state.ancestors[1].removeUsers; // Joi.in('removeUsers').path;
                                    if (testArray) {
                                        const test = testArray.includes(value);
    
                                        if (test) {
                                            throw new Error(
                                                'addUsers or removeUsers must not contain the same email'
                                            );
                                        }
                                    }
                                    return value;
                                })
                        )
                        .unique()
                        .messages({
                            'array.min':
                                'addUsers or removeUsers must contain at least 1 email',
                            'any.valid':
                                'addUsers or removeUsers must not contain the same email'
                        })
                        .example(['some.user@email.com', 'non.user@email.com'])
                }),
                removeUsers: Joi.array()
                    .items(Joi.string().email())
                    .unique()
                    .messages({
                        'array.unique':
                            'addUsers or removeUsers must contain a unique list of emails'
                    })
                    .example(['some.other.user@email.com'])
    })