Node.js + Joi how to display a custom error messag

2020-02-17 09:40发布

问题:

It seems pretty straight forward to validate user's input in Node.js RESTapi with Joi.

But the problem is that my app is not written in English. That means I need to send a custom written messages to the frontend user.

I have googled for this and only found issues.

Maybe could someone give a solution for this?

This is the code I am using to validate with the Joi system:

    var schema = Joi.object().keys({
      firstName: Joi.string().min(5).max(10).required(),
      lastName: Joi.string().min(5).max(10).required()
      ..
    });

    Joi.validate(req.body, schema, function(err, value) {
      if (err) {
        return catched(err.details); 
      }
    });

    function catched(reject) {
      res.json({
        validData: false,
        errors: reject
      });
    }

Plus, is there a way to use Joi in client side?

Thanks!

回答1:

Joi Version 14.0.0

const SchemaValidation = {
  coins: Joi.number()
    .required()
    .error(() => {
      return {
        message: 'Coins is required.',
      };
    }),
  challenge_name: Joi.string()
    .required()
    .error(() => {
      return {
        message: 'Challenge name is required.',
      };
    }),
  challengeType: Joi.string()
    .required()
    .error(() => {
      return {
        message: 'Challenge type is required.',
      };
    }),
  challengeDescription: Joi.string()
    .required()
    .error(() => {
      return {
        message: 'Challenge description is required.',
      };
    }),
};

In errors object you can get, error type and change message according.



回答2:

Extending on Ashish Kadam's answer, if you have many different error types, you can check which type of error is present, and set its message accordingly:

var schema = Joi.object().keys({
  firstName: Joi.string().min(5).max(10).required().error(errors => {
    errors.forEach(err => {
      switch (err.type) {
        case "any.empty":
          err.message = "Value should not be empty!";
          break;
        case "string.min":
          err.message = `Value should have at least ${err.context.limit} characters!`;
          break;
        case "string.max":
          err.message = `Value should have at most ${err.context.limit} characters!`;
          break;
        default:
          break;
      }
    });
    return errors;
  }),
  // ...
});

You can check the list of errors here: Joi 14.3.1 API Reference > Errors > List of errors

Also you can check the any.error reference for more information. Quoting the docs:

Overrides the default joi error with a custom error if the rule fails where:

  • err can be:
    • an instance of Error - the override error.
    • a function(errors), taking an array of errors as argument, where it must either:
      • return a string - substitutes the error message with this text
      • return a single object or an Array of it, where:
        • type - optional parameter providing the type of the error (eg. number.min).
        • message - optional parameter if template is provided, containing the text of the error.
        • template - optional parameter if message is provided, containing a template string, using the same format as usual joi language errors.
        • context - optional parameter, to provide context to your error if you are using the template.
      • return an Error - same as when you directly provide an Error, but you can customize the error message based on the errors.
  • options:
    • self - Boolean value indicating whether the error handler should be used for all errors or only for errors occurring on this property (true value). This concept only makes sense for array or object schemas as other values don't have children. Defaults to false.


回答3:

A solution I have found is to set:

var schema = Joi.object().keys({
  firstName: Joi.string().min(5).max(10).required().label("Your error message in here"),
  lastName: Joi.string().min(5).max(10).required()
  ..
});

Then print the label from the callback error variable



回答4:

You can use .error(new Error('message')), And its work for me

var schema = Joi.object().keys({
  firstName: Joi.string().min(5).max(10).required().error(new Error('Give your error message here for first name')),
  lastName: Joi.string().min(5).max(10).required().error(new Error('Give your error message here for last name'))
  ..
});

Joi.validate(req.body, schema, function(err, value) {
  if (err) {
    console.log(err.message)
    return catched(err.message); 
  }
});


回答5:

The current way (I personally find it better) is to use .messages() (or .prefs({messages})).

const Joi = require('@hapi/joi');

const joiSchema = Joi.object({
  a: Joi.string()
    .min(2)
    .max(10)
    .required()
    .messages({
      'string.base': `"a" should be a type of 'text'`,
      'string.empty': `"a" cannot be an empty field`,
      'string.min': `"a" should have a minimum length of {#limit}`,
      'any.required': `"a" is a required field`
    })
});

const validationResult = joiSchema.validate({ a: 2 }, { abortEarly: false });
console.log(validationResult.error); // expecting ValidationError: "a" should be a type of 'text'

Usage of .errors() is not recommended just to update default message with custom message.

.prefs({ messages }) is an elaborate way to provide more options as preferences. The other options for prefs are taken directly from options of .validate()

Further read: https://github.com/hapijs/joi/issues/2158


Update: I saw that the above explanation did not work out for some folks, so I have put up some code to test yourself. Check it here: https://runkit.com/embed/fnfaq3j0z9l2

Also updated the code snippet shared previously to have details from package inclusion, to usage, to calling the actual validation method.



回答6:

let schema = Joi.object({ foo: Joi.number().min(0).error(() => '"foo" requires a positive number') });

Docs link



回答7:

Solution to add custom messages: Simply add another chained function to throw error while defining your schema.
In your case

 firstName: Joi.string().min(5).max(10).required().error(new Error('I am a custom error and I know it!')),

Rest will remain same.

Solution to use Joi at client side (Your 2nd question)

Joi-Browser is the package which enables usage of the same schema at the client side.

Here is an interesting discussion you can have a look at.

Cheers!



回答8:

For anyone having a problem with

...messages is not a function

errors, you must install joi with npm install @hapi/joi, and importing it with @hapi/joi. I've made the mistake of installing joi without the @hapi/ prefix and it took me a while to find the error.



回答9:

let schema = Joi.object().keys({
   Joi.string().required().options({language: {any: {required: "First name is required"}}})
});


标签: node.js joi