检查猫鼬验证错误的最佳方法

Posted

技术标签:

【中文标题】检查猫鼬验证错误的最佳方法【英文标题】:Best way to check for mongoose validation error 【发布时间】:2013-01-02 15:22:24 【问题描述】:

我的用户模型有两个 validation 函数

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');

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');

它们以下列格式返回错误

 message: 'Validation failed',
  name: 'ValidationError',
  errors: 
     username: 
       message: 'Validator "USERNAME_TAKEN" failed for path username',
        name: 'ValidatorError',
        path: 'username',
        type: 'USERNAME_TAKEN'   

email 路径的错误类似。有没有比以下更聪明的方法来检查这些错误?

if (err && err.errors && err.errors.username)  ... 

这有点丑。

【问题讨论】:

【参考方案1】:

你为什么不使用validation方法as described in the API?

objectToSave.validate(function(err)           
  if (err) 
    // handle error
       
  else 
    // validation passed
  
);

【讨论】:

This method is called pre save and if a validation rule is violated, save is aborted and the error is returned to your callback. 这基本上就是我已经在做的事情了。我遇到的问题是处理err 没有太多麻烦。【参考方案2】:

从技术上讲,您必须首先检查错误名称,因为并非所有错误都以相同的方式处理。然后,您必须根据错误名称检查特定属性,如 ValidationError 附带的错误属性。

另外你将字段名放在错误类型中,这是多余的,最好使用相同的错误类型,因为在错误检查过程中你也会得到字段名。

所以你的代码可以是这样的:

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');

然后,错误检查程序:

if (err) 
  switch (err) 
    case err instanceof mongoose.Error.ValidationError:
      for (field in err.errors) 
        switch (err.errors[field].type) 
          case 'exists':
            ...
            break;
          case 'invalid':
            ...
            break;
          ...
        
      
      break;
    default:
      ...
  

如果你想缩短它,你有多种选择。如果您只有一种类型的验证,您可以这样做:

if (err) 
  if (err instanceof mongoose.Error.ValidationError) 
    for (field in err.errors) 
      ...
    
   else 
    // A general error (db, crypto, etc…)
    ...
  

错误检查过程的最小表达方式与您在帖子中所写的类似:

if (err) 
  for (field in err.errors) 
    ...
  

这将起作用,因为如果未定义错误,它将忽略 for。但是您在这里忽略了所有其他错误类型。

我也认为这些错误布局有点混乱,但不要指望在不久的将来会改变。

【讨论】:

ValidationError 是一般错误,由其他几个具有不同格式和/或属性的模块抛出。最好在错误检查过程中具体并检查err instanceof mongoose.Error.ValidationError【参考方案3】:

只需编写以下代码即可享受。

if (err) 
    console.log('Error Inserting New Data');
    if (err.name == 'ValidationError') 
        for (field in err.errors) 
            console.log(err.errors[field].message); 
        
    

【讨论】:

不是你想要在你的代码中随处可见的东西,但它会成为一个很好的辅助函数。【参考方案4】:

我发现这很有帮助,它可以在数组中显示所有错误。

例如,我提交了一个密码短且电子邮件无效的表单。

if (err && err.name === 'ValidationError') 
   err.toString().replace('ValidationError: ', '').split(',')

结果是这样的

[ 'Please provide a valid email address',
'The password should be at least 6 characters long' ]

如果您的错误消息中包含逗号 ,,请尝试不使用 .split(',')

不需要for 循环。确保您的架构中有验证错误消息。对于上面的例子,我有

const validateEmail = email => 
  const re = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w2,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'] ,
   ...
);

【讨论】:

【参考方案5】:

我使用 AngularJS,所以ngRepeat 在 Web 表单上显示我的验证错误。我需要做的就是返回一组错误消息。

有时 Mongoose 会抛出一个不是验证错误的错误,在这种情况下 err.errors 对象将不存在。我记录执行错误。我仍然使用 Web 表单上的相同位置向用户显示执行错误。

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;

【讨论】:

【参考方案6】:

通过阅读所有这些答案,我认为最好创建实用函数并重用它:

这是处理ValidationError 的函数,通过向客户端发送带有验证消息的所需响应,并可选择使用console.log 在控制台中显示消息。

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 )

然后在我们要处理错误的控制器中,我们检查err.name 是否为ValidationError,如果是,我们使用上面的实用函数。

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' )
)

然后客户端将收到验证错误作为响应:

curl\
-H 'Content-Type: application/json'\
-d '"email": "foo", "password": "barbaz"'\
http://localhost:3000/user/new

输出:

"messages":["Email validation failure"]

【讨论】:

【参考方案7】:

这是我处理猫鼬验证错误的独特方法

代码仍在进行中,一旦准备好我会更新它,或者您可以贡献扩展我的代码。

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
);

【讨论】:

【参考方案8】:

方法#1

我对这种方法的最佳猜测是使用具有基于承诺的回报的广义验证器, 希望对以后有所帮助

function validateDoc(model,fieldName) 
  return new Promise((resolve, reject) => 
    model.validate(err => 
      if (err) 
        return reject(err.errors[fieldName]);
       else 
        return resolve(model);
      
    );
  )


// Access error message in catch() or get the validated doc in then()

validateDoc(model,fieldName)
           .then((model) => console.log(model))
           .catch((message) => console.warn(message))

方法 #2

const userSchema = new Schema(
  name: 
    type:String,
    required:[true,'Name is required.'],
    validate:
      validator:(name) =>  name.length <= 2 
      message:'Name must be longer than two characters'
    
  
)
const User = mongoose.model('user',userSchema)

使用 validate:Object 内部架构与 validator:functionmessage:String

稍后当你尝试保存记录时,它会在 catch 函数中显示验证错误对象

举例

const newUser = new User( name: undefined );

newUser.save().catch( (  errors  ) =>  

let errorBag = [];

Object.keys(errors).forEach((fieldName) => 

errorBag.push( [fieldName]:errors[fieldName].message )

);

 // All the errors with the **fieldName** and  **errorMessages** 

console.log(errorBag);  

   )

【讨论】:

以上是关于检查猫鼬验证错误的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

如何修复“需要路径,验证错误”,猫鼬,节点

如何修复“需要路径,验证错误”,猫鼬,节点

Nativescript Vue + Firebase 身份验证:检查用户是不是在每个组件中进行身份验证的最佳方法?

将错误消息从猫鼬验证转换为用户友好的消息

猫鼬通过承诺返回验证还是我需要实现它?

本地护照和本地护照猫鼬的身份验证错误