如何为Express Validator的Schema验证设置自定义错误消息?
Hey there! Let's sort out those mixed-up error messages in your express-validator setup. The root problem here is that you're using a single global errorMessage for each field, but every validation rule—including your async checks for duplicate emails/usernames—needs its own specific error message to avoid cross-over.
Why Your Current Setup Is Failing
When you set a top-level errorMessage on a field, it acts as a fallback for all validation failures on that field. If you don't define individual messages for rules like isEmail, notEmpty, or your async custom checks, every failure (whether it's a bad email format or a duplicate entry) will default to that one message. That's why you're seeing "This email is already in use" even when the DNS validation fails.
Corrected Validation Schema Example
Here's how to update your schema to assign specific messages to each rule. I'll include fixes for email and username (since those were your main pain points) along with your existing fields:
const { checkSchema } = require('express-validator'); const validation_rules = checkSchema({ company_name: { trim: true, isLength: { options: { min: 3, max: 50 }, errorMessage: 'Company Name should be at least 3 chars long and maximum of 50 chars' } }, profile_name: { trim: true, isLength: { options: { min: 3, max: 50 }, errorMessage: 'Public Profile Name should be at least 3 chars long and maximum of 50 chars' } }, description: { trim: true, isLength: { options: { min: 2, max: 200 }, errorMessage: 'Company Description should be at least 2 chars long and maximum of 200 chars' } }, company_street_address: { trim: true, isLength: { options: { min: 3, max: 100 }, errorMessage: 'Company Address should be at least 3 chars long and maximum of 100 chars' } }, // Fixed Email Validation email: { trim: true, isEmail: { options: { require_tld: true // Ensures DNS validation for the email domain }, errorMessage: 'Not a valid email' // Triggers when format/DNS fails }, custom: { options: async (value) => { // Replace with your actual duplicate check logic const existingUser = await User.findOne({ email: value }); if (existingUser) { throw new Error('This email is already in use'); } }, errorMessage: 'This email is already in use' // Triggers when email is taken } }, // Fixed Username Validation username: { trim: true, notEmpty: { errorMessage: 'Please enter username' // Triggers when username is empty }, isLength: { options: { max: 25 }, errorMessage: 'Username cannot exceed 25 characters' // Triggers when too long }, custom: { options: async (value) => { // Replace with your actual duplicate check logic const existingUser = await User.findOne({ username: value }); if (existingUser) { throw new Error('This username is already in use'); } }, errorMessage: 'This username is already in use' // Triggers when username is taken } } });
Key Changes Explained
- Per-Rule Error Messages: Each validation rule (
isLength,isEmail,notEmpty,custom) now has its ownerrorMessage. This ensures each failure scenario returns the correct message. - Async Custom Checks: For your duplicate checks, the
customrule gets its ownerrorMessage(and we also throw an explicit error inside the async function, which acts as a backup). - Removed Top-Level Field Error Messages: Instead of a global message for the field, each rule defines its own, so there's no fallback that overrides specific messages.
Verifying Error Messages
Make sure you're collecting errors correctly in your route handler using validationResult:
const { validationResult } = require('express-validator'); app.post('/your-endpoint', validation_rules, (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } // Proceed with your logic });
Each entry in errors.array() will have a msg property matching the specific rule's error message that failed.
内容的提问来源于stack exchange,提问作者Mohsin Khan

