Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.when() in joi validation, to validate one key based on another key

Admin will create users, and while doing so he will enter some random string as a password. When admin edit the existing user, he don't need to enter any password unless he wants to change it. If the admin doesn't enter any password, then the old password will be used.

So i am trying to use .when() to handle this case. When _id exists in the payload (which is possible only when the user exists), then we should make the password field optional or else password is required.

Here is my Joi validation

const usersJoiSchema = Joi.object({
  _id: Joi.string().optional(),
  firstName: Joi.string().required(),
  lastName: Joi.string().required(),
  email: Joi.string().required(),
  password: Joi.string().when('_id', { is: Joi.exist(), then: Joi.optional(), otherwise: Joi.required() })
})

Joi have a method .when in case of such cases. But for some strange reason it is giving me

{"statusCode":500,"error":"Internal Server Error","message":"An internal server error occurred"}

as the response of the api, and there is nothing in the server console. I tried to compare the string length for _id as well instead of exists() and i have also tried

password: Joi.string().when('_id', { is: Joi.string().required(), then: Joi.string().optional(), otherwise: Joi.string().required() }),

password: Joi.string().when('_id', { is: Joi.string(), then: Joi.string().optional(), otherwise: Joi.string().required() }),

for password key, but still the same issue.

If any one has any kind of idea on this issue, please help me.

like image 528
Rajeshwar Avatar asked Jan 09 '19 14:01

Rajeshwar


People also ask

Which is better express validator or Joi?

Joi can be used for creating schemas (just like we use mongoose for creating NoSQL schemas) and you can use it with plain Javascript objects. It's like a plug n play library and is easy to use. On the other hand, express-validator uses validator. js to validate expressjs routes, and it's mainly built for express.

Should I use Joi With mongoose?

Mongoose specific options can be specified in the meta object (see below). Arrays with items of different types will end up with the Mongoose type Mixed . Ideally, Joi schemas shouldn't have to contain Mongoose specific types, such as Mongoose. Schema.


2 Answers

Well, I created a simple test and all conditions are passed according to your requirements. I believe there is something else in your code occurs that error. Here is my test code, please take a look.

const Lab = require('lab');
const lab = exports.lab = Lab.script();
const describe = lab.describe;
const it = lab.it;
const expect = require('code').expect;
const Joi = require('joi');

const usersJoiSchema = Joi.object({
    _id: Joi.string().optional(),
    firstName: Joi.string().required(),
    lastName: Joi.string().required(),
    email: Joi.string().required(),
    password: Joi.string().when('_id', {is: Joi.exist(), then: Joi.optional(), otherwise: Joi.required()})
});

describe('Validator usersJoiSchema checks', () => {

    it('It should save new user without id', () => {
        const result = Joi.validate({
            firstName: "Hello",
            lastName: "World",
            email: "[email protected]",
            password: "123456"
        }, usersJoiSchema, {abortEarly: false});
        expect(result.error).to.null();
        expect(result.error).to.not.exist();
    });

    it('It should update user without password field when id included', () => {
        const result = Joi.validate({
            _id: "some-id-string-here",
            firstName: "Hello",
            lastName: "World",
            email: "[email protected]",
        }, usersJoiSchema, {abortEarly: false});
        expect(result.error).to.null();
        expect(result.error).to.not.exist();
    });


    it('It should fail when id is empty and no password provided', () => {
        const result = Joi.validate({
            firstName: "Hello",
            lastName: "World",
            email: "[email protected]",
        }, usersJoiSchema, {abortEarly: false});
        expect(result.error).to.not.null();
        expect(result.error).to.exist();
    });
    it('It should fail when id is empty and password is also empty', () => {
        const result = Joi.validate({
            firstName: "Hello",
            lastName: "World",
            email: "[email protected]",
            password: "",
        }, usersJoiSchema, {abortEarly: false});
        expect(result.error).to.not.null();
        expect(result.error).to.exist();
    });
});

Here is the test command

> lab --coverage-exclude test/data -m 5000n -a code -P "simple" "test/validators"

  ....

4 tests complete
Test duration: 8 ms
Assertions count: 8 (verbosity: 2.00)
No global variable leaks detected
like image 101
metoikos Avatar answered Sep 30 '22 18:09

metoikos


  _id: Joi.string(),
  password: Joi.string().when("_id", {
     is: Joi.exist(),
     then: Joi.required()
  })

With the above, Joi will ensure that password is required whenever _id exists

like image 21
Princewill Iroka Avatar answered Sep 30 '22 18:09

Princewill Iroka