node.js - hobba - La mejor forma de verificar el error de validación de la mangosta
hartico (6)
¿Por qué no usas el método de validation
como se describe en la API ?
objectToSave.validate(function(err) {
if (err) {
// handle error
}
else {
// validation passed
}
});
Tengo dos funciones de validation para mi modelo de usuario
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'');
y lo mismo para el username
de 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'');
Devuelven errores en el siguiente formato
{ message: ''Validation failed'',
name: ''ValidationError'',
errors:
{ username:
{ message: ''Validator "USERNAME_TAKEN" failed for path username'',
name: ''ValidatorError'',
path: ''username'',
type: ''USERNAME_TAKEN'' } } }
El error para la ruta del email
es similar. ¿Hay alguna forma más inteligente de verificar esos errores que la siguiente?
if (err && err.errors && err.errors.username) { ... }
Esto es feo
Al leer todas estas respuestas, considero que es lo mejor para crear la función de utilidad y reutilizarla como tal:
Esta es la función que maneja ValidationError
enviando la respuesta deseada al cliente con mensajes de validación, y opcionalmente usa console.log
para mostrar los mensajes en la consola.
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 })
}
Luego, en el controlador donde queremos manejar el error, verificamos si err.name
es ValidationError
, y si es así, usamos la función de utilidad desde arriba.
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'' })
})
Entonces el cliente obtendría errores de validación en respuesta como tal:
curl/
-H ''Content-Type: application/json''/
-d ''{"email": "foo", "password": "barbaz"}''/
http://localhost:3000/user/new
Salida:
{"messages":["Email validation failure"]}
Me pareció útil, que muestra todos los errores en una matriz.
Por ejemplo, envié un formulario con una contraseña corta y un correo electrónico no válido.
if (err && err.name === ''ValidationError'') {
err.toString().replace(''ValidationError: '', '''').split('','')
}
Lo que resulta en esto
[ ''Please provide a valid email address'',
''The password should be at least 6 characters long'' ]
Si tiene una coma ,
en sus mensajes de error intente sin .split('','')
No hay necesidad for
bucles. Asegúrese de tener mensajes de error de validación en su esquema. Para el ejemplo anterior, tengo
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''] },
...
});
Simplemente escribe el siguiente código y disfruta.
if (err) {
console.log(''Error Inserting New Data'');
if (err.name == ''ValidationError'') {
for (field in err.errors) {
console.log(err.errors[field].message);
}
}
}
Técnicamente debe verificar primero el nombre del error porque no todos los errores se manejan de la misma manera. Luego, según el nombre del error, debe verificar propiedades particulares, como la propiedad de errores que viene con ValidationError.
También pones el nombre del campo en el tipo de error y esto es redundante, es mejor usar el mismo tipo de error porque en el procedimiento de comprobación de errores obtendrás también el nombre del campo.
Entonces su código puede ser algo así como:
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'');
Y luego, el procedimiento de comprobación de errores:
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 quiere acortar esto, tiene varias opciones. Si solo tiene un tipo de validación, puede hacerlo así:
if (err) {
if (err.name == ''ValidationError'') {
for (field in err.errors) {
...
}
} else {
// A general error (db, crypto, etc…)
...
}
}
La expresión mínima del procedimiento de verificación de errores sería similar a la que escribió en su publicación:
if (err) {
for (field in err.errors) {
...
}
}
Esto funcionará porque si no se definen los errores, simplemente ignorará el for. Pero está ignorando todos los otros tipos de error aquí.
También creo que estos diseños de error son un poco molestos, pero no esperes que esto cambie en un futuro cercano.
Yo uso AngularJS, entonces ngRepeat
muestra mis errores de validación en el formulario web. Todo lo que necesito hacer es devolver una serie de mensajes de error.
En ocasiones, Mongoose lanzará un error que NO es un error de validación, y en este caso el objeto err.errors no estará presente. Registro el error de ejecución. Todavía utilizo el mismo lugar en el formulario web para mostrar el error de ejecución al usuario.
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;
}