Search code examples
javascriptnode.jshapi.jsjoi

JOI validation is not returning all the errors despite setting abort early false


i've been trying to validate my payload via joi schema. But it's not returning the error what I've written in schema rather it's showing only one error. Even if i give payload like name=int only one custom error is showing up despite giving 2nd input aka username a integer value:

{ "statusCode": 400,

"error": "Bad Request",

"message": "name expecting a string" }

rather it should have printed

{ "statusCode": 400,

"error": "Bad Request",

"message": "name expecting a string"/"username expecting a string" }

this is my code: server.js

    const server = Hapi.server({
        port: 3000,
        routes: {
            validate: {
                options: {
                    abortEarly: false
                  },
                failAction: async (request, response, err) => {
                    throw Boom.badRequest(err.message);
                },
            },

        },
    });

joi-schmea.js

const NamePayload = Joi.object().keys({
    name: Joi.string().required().error(new Error('name expecting a string')),
    username: Joi.string().required().error(new Error('username expecting a string')),
    age: Joi.integer().required().error(new Error('age expecting a number')),

});

routes.js:

validate: {
        payload: Schema.NamePayload,

      },

I want postman to show all the error message not only the first error message. And I also dont wanna use default error message child must be string/int type error that's why I'm using new error. I've read all the stackoverflow article about that error but nothing solved my problem . This is the hapi and joi version im using:

@hapi/joi: ^15.0.3,

@hapi/hapi: ^18.3.1,


Solution

  • For what I understand, each Joi error throws a ValidationError that contains a key details, which is an array of errors, each one, among other things, has your custom error message, and by doing new Error() in your schema you are overriding that key details. So, this is what I suggest you to do:

    Replace your schema errors with this:

    Joi.object().keys({
        name: Joi.string().required().error(() => 'name expecting a string'),
        username: Joi.string().required().error(() => 'username expecting a string'),
        age: Joi.number().integer().required().error(() => 'age expecting a number'),
    });
    

    And then in your failAction concat those messages that are inside err.details:

    failAction: async (request, response, err) => {
        throw Boom.badRequest(err.details.map((error) => error.message).join('/'));
    }
    

    For this payload:

    {
       "name": 10
    }
    

    You will get this response:

    {
       "statusCode": 400,
       "error": "Bad Request",
       "message": "name expecting a string/username expecting a string/age expecting a number"
    }