如何在Node.js(Joi ^17.3.0版本)中验证嵌套对象并自定义错误提示信息
To get concise error messages like firstname required instead of the full path-based details.firstname is required, you have a few solid options with Joi v17.3.0:
Option 1: Per-Field Custom Messages
The most straightforward approach is to explicitly define custom error messages for each required field. This gives you full control over each message:
const Joi = require("joi"); const Validation = (data) => { const schema = Joi.object({ details: Joi.object({ firstname: Joi.string() .required() .messages({ 'any.required': 'firstname required' }), lastname: Joi.string() .required() .messages({ 'any.required': 'lastname required' }) }) }); return schema.validate(data); }; module.exports = { Validation };
Option 2: Use Labels + Global Message Template
If you have multiple fields and want to avoid repetition, set a custom label for each nested field and define a global message template for required fields:
const Joi = require("joi"); const Validation = (data) => { const schema = Joi.object({ details: Joi.object({ firstname: Joi.string().required().label('firstname'), lastname: Joi.string().required().label('lastname') }) }).messages({ 'any.required': '{{#label}} required' }); return schema.validate(data); }; module.exports = { Validation };
Here, the label overrides the full path in error messages, and the global messages config ensures all required fields use the same concise format.
Option 3: Post-Process Error Messages
For a scalable solution that works across all nested fields without modifying each one, you can post-process the validation error object to strip the parent path prefix:
const Joi = require("joi"); const Validation = (data) => { const schema = Joi.object({ details: { firstname: Joi.string().required(), lastname: Joi.string().required(), }, }); const result = schema.validate(data); // Modify error messages if present if (result.error) { result.error.details = result.error.details.map(detail => { // Get the last part of the field path (e.g., 'firstname' from ['details', 'firstname']) const fieldName = detail.path.at(-1); detail.message = `${fieldName} required`; return detail; }); } return result; }; module.exports = { Validation };
This approach automatically adjusts all required field errors to use just the field name, regardless of how deeply nested they are.
Testing the Solution
When you omit the firstname field in your request body, all three methods will return the error message firstname required instead of the original path-based message.
内容的提问来源于stack exchange,提问作者Arun M

