J'ai deux validation fonctions pour mon modèle d'utilisateur
User.schema.path('email').validate(function(value, respond) {
User.findOne({email: value}, function(err, user) {
if(err) throw err;
if(user) return respond(false);
respond(true);
});
}, 'EMAIL_EXISTS');
et le même pour username
User.schema.path('username').validate(function(value, respond) {
User.findOne({username: value}, function(err, user) {
if(err) throw err;
if(user) return respond(false);
respond(true);
});
}, 'USERNAME_TAKEN');
Ils renvoient des erreurs dans le format suivant
{ message: 'Validation failed',
name: 'ValidationError',
errors:
{ username:
{ message: 'Validator "USERNAME_TAKEN" failed for path username',
name: 'ValidatorError',
path: 'username',
type: 'USERNAME_TAKEN' } } }
L'erreur pour le chemin email
est similaire. Existe-t-il un moyen plus intelligent de vérifier ces erreurs que les suivantes?
if (err && err.errors && err.errors.username) { ... }
C'est un peu moche.
Techniquement, vous devez d'abord vérifier le nom de l'erreur car toutes les erreurs ne sont pas traitées de la même manière. Ensuite, en fonction du nom de l'erreur, vous devez vérifier certaines propriétés, en tant que propriété errors fournie avec ValidationError.
Aussi, vous mettez le nom du champ dans le type d'erreur et c'est redondant, il est préférable d'utiliser le même type d'erreur car dans la procédure de vérification d'erreur, vous obtiendrez également le nom du champ.
Donc, votre code peut être quelque chose comme:
User.schema.path('email').validate(function(value, respond) {
User.findOne({email: value}, function(err, user) {
if(err) throw err;
if(user) return respond(false);
respond(true);
});
}, 'exists');
User.schema.path('username').validate(function(value, respond) {
User.findOne({username: value}, function(err, user) {
if(err) throw err;
if(user) return respond(false);
respond(true);
});
}, 'exists');
Et puis, la procédure de vérification d'erreur:
if (err) {
switch (err.name) {
case 'ValidationError':
for (field in err.errors) {
switch (err.errors[field].type) {
case 'exists':
...
break;
case 'invalid':
...
break;
...
}
}
break;
default:
...
}
}
Si vous voulez raccourcir cela, vous avez plusieurs options. Si vous n'avez qu'un seul type de validation, vous pouvez le faire comme ceci:
if (err) {
if (err.name == 'ValidationError') {
for (field in err.errors) {
...
}
} else {
// A general error (db, crypto, etc…)
...
}
}
L'expression minimale de la procédure de vérification d'erreur serait semblable à celle que vous avez écrite dans votre message:
if (err) {
for (field in err.errors) {
...
}
}
Cela fonctionnera car si les erreurs ne sont pas définies, elles ignoreront simplement le for. Mais vous ignorez tous les autres types d'erreur ici.
Je pense également que ces dispositions d'erreur sont un peu gênantes, mais ne vous attendez pas à ce que cela change dans un proche avenir.
Il suffit d'écrire le code suivant et d'en profiter.
if (err) {
console.log('Error Inserting New Data');
if (err.name == 'ValidationError') {
for (field in err.errors) {
console.log(err.errors[field].message);
}
}
}
J'utilise AngularJS, donc ngRepeat
affiche mes erreurs de validation sur le formulaire Web. Tout ce que j'ai à faire est de renvoyer un tableau de messages d'erreur.
Parfois, Mongoose génère une erreur qui n'est PAS une erreur de validation et dans ce cas, l'objet err.errors ne sera pas présent. Je me connecte l'erreur d'exécution. J'utilise toujours le même endroit sur le formulaire Web pour afficher l'erreur d'exécution à l'utilisateur.
var makeMongooseErrorMsgArray = function(err){
var msgArray = [];
if (err.errors) { // validation errors
$.each(err.errors, function (key, val) {
msgArray.Push(val.message);
});
} else if (err.message){ // should be execution error without err.errors
errLogr.log(err); // log execution errors
msgArray.Push(err.message);
} else {
msgArray.Push('Unknown error');
}
return msgArray;
}
J'ai trouvé cela utile qui affiche toutes les erreurs dans un tableau.
Par exemple, j'ai soumis un formulaire avec un mot de passe court et un email invalide.
if (err && err.name === 'ValidationError') {
err.toString().replace('ValidationError: ', '').split(',')
}
Quel est le résultat
[ 'Please provide a valid email address',
'The password should be at least 6 characters long' ]
Si vous avez une virgule ,
dans vos messages d'erreur, essayez sans .split(',')
Pas besoin de boucles for
. Assurez-vous que votre schéma contient des messages d'erreur de validation. Pour l'exemple ci-dessus, j'ai
const validateEmail = email => {
const re = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
return re.test(email);
};
const Schema = mongoose.Schema;
const userSchema = new Schema({
...
email: {
type: String,
trim: true,
required: 'Email address is required',
validate: [validateEmail, 'Please provide a valid email address'],
},
password: { type: String, set: encryptPassword, maxlength: [6, 'The password should be at least {MAXLENGTH} characters long'] },
...
});
Pourquoi n'utilisez-vous pas la méthode validation
telle que décrite dans l'API ?
objectToSave.validate(function(err) {
if (err) {
// handle error
}
else {
// validation passed
}
});
En lisant toutes ces réponses, j'estime qu'il est préférable de créer une fonction utilitaire et de la réutiliser comme telle:
Il s’agit de la fonction qui gère ValidationError
en envoyant la réponse souhaitée au client avec des messages de validation et utilise éventuellement console.log
pour afficher les messages dans la console.
function handleValidationError(err, res, consoleLog = false){
const messages = []
for (let field in err.errors) {
messages.Push(err.errors[field].message)
consoleLog && console.log(err.errors[field].message)
}
res.status(422).json({ messages })
}
Ensuite, dans le contrôleur où nous voulons gérer les erreurs, nous vérifions si err.name
est ValidationError
et, dans l’affirmative, nous utilisons la fonction d’utilité d’en haut.
user.save((err) => {
if (err) {
if (err.name === 'ValidationError') return handleValidationError(err, res) // here
return res.status(500).json({ message: 'Error while creating new user' })
}
return res.status(201).json({ message: 'User created' })
})
Ensuite, le client obtiendrait des erreurs de validation en réponse en tant que tel:
curl\
-H 'Content-Type: application/json'\
-d '{"email": "foo", "password": "barbaz"}'\
http://localhost:3000/user/new
Sortie:
{"messages":["Email validation failure"]}
Voici ma façon unique de gérer les erreurs de validation de la mangouste
Le code est toujours en cours une fois qu'il est prêt, je le met à jour ou vous pouvez contribuer à étendre mon code.
let message = "";
let title = "Validation Error";
let code = 400;
let requiredFields = [];
for (let field in err.errors) {
let subMsg = ""
if (err.errors[field].kind === "required") {
requiredFields.Push(field)
}
}
if (requiredFields.length > 0) {
message = "Following fields are required: " + requiredFields.join(", ");
} else {
message = "Unknown";
}
res.status(code).json({
status: code,
message: message,
title: title
});