Aks
Aks

Reputation: 1234

How to manage self created error message instead of using default celebrate @hapi/joi code

I have two files, one is api.js and other one is handler.js. For schema handling I am using celebrate module @hapi/joi

On api.js I wrote only the API name

On handler.js I wrote the API functionality.

api.js
//JOI Schema Validator Middleware.
router.use(celebrate({
    body: Joi.object().keys({
        post: Joi.string().max(10),
        userid: Joi.string(),
    })
}));

const handler = require('./handler');

router.post('/createpost', handler.createPost);

router.use(errors());

module.exports = router;

By this if error happens then i got the Response like this

{"statusCode":400,"error":"Bad Request","message":"child \"post\" fails because [\"post\" length must be less than or equal to 10 characters long]","validation":{"source":"body","keys":["post"]}}

I just want to Convert this error into my own format error i.e something like this

{error: true, status: 500, message: 'validation error', version: x.x.2}

The default joi error is generated through router.use(errors()); this module. How I modify this? Any help or suggestion is really appreciated.

Upvotes: 4

Views: 6301

Answers (2)

Gee VB
Gee VB

Reputation: 223

TL;DR: Create your own 'errors()' function.

You have probably managed to change it by now, but just like me, I had the exact same issue and found this answerless thread.

Well, for future readers, celebrate errors() is nothing else than a function, more exactly, this one:

(err, req, res, next) => {
  // If this isn't a Celebrate error, send it to the next error handler
  if (!isCelebrate(err)) {
    return next(err);
  }

  const {
    joi,
    meta,
  } = err;

  const result = {
    statusCode: 400,
    error: 'Bad Request',
    message: joi.message,
    validation: {
      source: meta.source,
      keys: [],
    },
  };

  if (joi.details) {
    for (let i = 0; i < joi.details.length; i += 1) {
      const path = joi.details[i].path.join('.');
      result.validation.keys.push(EscapeHtml(path));
    }
  }
  return res.status(400).send(result);
}

There, you can see the response object 'result' being declared and how it's done. So, to change the output of it, you have to not use errors() and create your own function to handle it.

So, I declared a new function:

  private errorHandling = (err, req, res, next) => {
    if (isCelebrate(err)) {
        return res.send({
            statusCode: 400,
            message: err.joi.message
        });
    }
    
    return next(err);
  }

You can obviously change the above to suit your needs.


Update

Celebrate changed their error structure to a CelebrateError, now you need access the error details using:

  const errorBody = err.details.get('body'); // 'details' is a Map()
  const { details: [errorDetails] } = errorBody;

instead of the err.joi. The message property remains the same.


Then, instead of using app.use(errors()) I used app.use(this.errorHandling), and now I get the celebrate response formatted as I want to.

Upvotes: 9

Vyk
Vyk

Reputation: 151

After some research, I found out it can be solved 2 ways:

[Segments.BODY]: Joi.object().keys({
value: Joi.string().required().error(new Error('Value is required and has to be a text!')),
})

or

[Segments.BODY]: Joi.object().keys({
password: Joi.string().required().pattern(new RegExp('^[a-zA-Z0-9]{3,30}$')).min(8).label('Password').messages({
    'string.pattern.base': 'Your {#label} does not matche the suggested pattern',
    'string.base': `Your {#label} should match the suggested pattern`,
    'string.empty': `Your {#label} can not be empty`,
    'string.min': `Your {#label} has to be at least {#limit} chars`,
    'any.required': `Your {#label} is required`,
}),

})

Upvotes: 1

Related Questions