Подтвердить что ты не робот

Обработка ошибок проверки Mongoose - где и как?

Я пытаюсь решить, как я хочу обрабатывать ошибки проверки в Mongoose.

Пользовательские сообщения об ошибках с использованием node -validator

Я определил свои собственные правила проверки, используя node-validator, например:

UserSchema.path('username')
  .validate(function (username) {
    return validator.check(username).notEmpty()
  }, 'Username cannot be blank')

Будет генерироваться ошибка, которая выглядит так:

  username: 
   { message: 'Validator "Username cannot be blank" failed for path username',
     name: 'ValidatorError',
     path: 'username',
     type: 'Username cannot be blank' },

Использование средства проверки соответствия мангуста

Однако node -validator предоставляет свои собственные сообщения об ошибках. Если я использую модуль mongoose-validator Node, чтобы подключить node -validator непосредственно к моей схеме, я могу напрямую использовать эти сообщения об ошибках вместо:

var UserSchema = new Schema({
  name: { type: String, validate: [validate('notEmpty')] }
});

Будет создано сообщение об ошибке:

  name: 
   { message: 'Validator "String is empty" failed for path name',
     name: 'ValidatorError',
     path: 'name',
     type: 'String is empty' } }

Здесь я также могу предоставить собственное сообщение об ошибке:

var UserSchema = new Schema({
  name: { type: String, validate: [validate({message: 'Name cannot be blank' }, 'notEmpty')] }
});

флаг Mongoose required

Mongoose позволяет вам определить поле по мере необходимости:

var UserSchema = new Schema({
  name: { type: String, required: true }
});

Будет создано сообщение об ошибке:

  name: 
   { message: 'Validator "required" failed for path name',
     name: 'ValidatorError',
     path: 'name',
     type: 'required' } }

Вопрос

Кажется, что эти валидаторы хотят использовать свои встроенные сообщения об ошибках. Например, я хочу объявить поле как required, как показано выше, но я не могу найти способ настройки сообщения об ошибке. И модуль проверки валидации mongoose не поддерживал пользовательские сообщения до самого последнего времени, что заставляет меня думать, что они являются анти-шаблонами на уровне модели.

Какой лучший способ реализовать эти валидаторы? Должен ли я позволить им генерировать собственные ошибки, а затем каким-то образом их интерпретировать?

4b9b3361

Ответ 1

На данный момент кажется логичным согласиться с тем, как мангуст обрабатывает ошибки.

Вы не хотели бы, чтобы ваши модели обрабатывали сообщения об ошибках. Уровень представления (контроллеры?) Должен полагаться на type чтобы решить, какое сообщение лучше всего отображать (удобнее для i18n).

Существует также случай, когда проверка может происходить с использованием промежуточного программного обеспечения. В этом случае сообщение об ошибке, которое появится на вашем контроллере, это то, что вы передаете обратному вызову next().

Таким образом, в случае промежуточного программного обеспечения, хотя и не документированного, для того, чтобы поддерживать согласованный API валидации для ваших моделей, вы должны напрямую использовать конструкторы Mongoose Error:

var mongoose = require('mongoose');
var ValidationError = mongoose.Error.ValidationError;
var ValidatorError  = mongoose.Error.ValidatorError;

schema.pre('save', function (next) {
  if (/someregex/i.test(this.email)) {
    var error = new ValidationError(this);
    error.errors.email = new ValidatorError('email', 'Email is not valid', 'notvalid', this.email);
    return next(error);
  }

  next();
});

Таким образом, вам гарантируется согласованная обработка ошибок проверки, даже если ошибка проверки происходит из промежуточного программного обеспечения.

Чтобы правильно сопоставить сообщения об ошибках с типами, я бы создал перечисление, которое будет действовать как статическая карта для всех возможных типов:

// my controller.js

var ValidationErrors = {
  REQUIRED: 'required',
  NOTVALID: 'notvalid',
  /* ... */
};


app.post('/register', function(req, res){
  var user = new userModel.Model(req.body);

  user.save(function(err){
    if (err) {
      var errMessage = '';

      // go through all the errors...
      for (var errName in err.errors) {
        switch(err.errors[errName].type) {
          case ValidationErrors.REQUIRED:
            errMessage = i18n('Field is required');
            break;
          case ValidationErrors.NOTVALID:
            errMessage = i18n('Field is not valid');
            break;
        }
      }
      res.send(errMessage);

    }
  });
});

Ответ 2

Я знаю, что плагины валидатора, вероятно, полезны, но я думаю, что валидация мангуста более пугающая, чем на самом деле сложная. Это определенно выглядит сложным снаружи, но как только вы начинаете разрывать его, это не так уж и плохо.

Если вы ознакомитесь с приведенным ниже кодом, вы увидите пример того, как пользовательское сообщение об ошибке может быть возвращено с помощью встроенных валидаторов.

Все, что вам нужно сделать, это установить второй параметр, с вашим собственным сообщением об ошибке, при настройке ваших полей.

Оформить заказ required и minlength и maxlength поле ниже, чтобы увидеть, как я установку пользовательских сообщений об ошибках, а затем проверить методы ниже того, как объект ошибки можно получить или отправить к переднему концу:

// Grab dependencies:
var mongoose = require('mongoose');

// Setup a schema:
var UserSchema = new mongoose.Schema (
    {
        username: {
            type: String,
            minlength: [2, 'Username must be at least 2 characters.'],
            maxlength: [20, 'Username must be less than 20 characters.'],
            required: [true, 'Your username cannot be blank.'],
            trim: true,
            unique: true,
            dropDups: true,
        }, // end username field
    },
    {
        timestamps: true,
    },
);

// Export the schema:
module.exports = mongoose.model('User', UserSchema);

Выше настраивает наши поля для пользовательских сообщений об ошибках. Но как нам получить к ним доступ или отправить их нашему клиенту? В нашем контроллере сервера может быть настроен следующий метод, данные ответа которого отправляются обратно в angular:

var myControllerMethods = {
    register : function(req, res) {
        // Create a user based on the schema we created:
        User.create(req.body)
            .then(function(newUser) {
                console.log('New User Created!', newUser);
                res.json(newUser);
            })
            .catch(function(err) {
                if (err.name == 'ValidationError') {
                    console.error('Error Validating!', err);
                    res.status(422).json(err);
                } else {
                    console.error(err);
                    res.status(500).json(err);
                }
            })
    },
};

Если вы запустили приведенный выше код, и ни один из наших валидаторов mongoose не прошел, объект error (err) будет захвачен .catch() в обещании. Если вы запишете эту ошибку в консоль, то увидите, что в этом объекте есть наше пользовательское сообщение, в зависимости от того, какая ошибка помечена.

Примечание. Приведенный выше пример предназначен только для добавления пользовательских проверочных сообщений в уже встроенные проверки, которыми обладает Mongoose (например, required, minlength, maxlength и т.д.).

Если вы хотите создать более сложные валидации, такие как валидация полей по шаблонам регулярных выражений и т.п., Вам придется создавать собственные функции validator.

Посмотрите раздел "Пользовательские валидаторы" по этой ссылке, чтобы найти отличный пример того, как добавить валидатор прямо в ваше поле: http://mongoosejs.com/docs/validation.html.

Примечание: Вы также можете использовать "ловушки предварительного сохранения" и "методы экземпляра", но это выходит за рамки этого вопроса, и встроенные валидаторы и "Пользовательские валидаторы" (ссылка выше) являются более простыми маршрутами.

Надеюсь это поможет!

Ответ 3

От Mongoose: https://github.com/leepowellcouk/mongoose-validator

Сообщения об ошибках Пользовательские сообщения об ошибках теперь возвращаются в 0.2.1 и могут быть установлены через объект опций:

validate({message: "String should be between 3 and 50 characters"}, 'len', 3, 50)


Как я это сделал:

var emailValidator = [validate({message: "Email Address should be between 5 and 64 characters"},'len', 5, 64), validate({message: "Email Address is not correct"},'isEmail')];

var XXXX = new Schema({
email : {type: String, required: true, validate: emailValidator} }); 

Мой внешний интерфейс имеет дело с обязательным требованием, поэтому я никогда не ожидаю, что ошибка "требуемого" мангуста сделает его доступным пользователю, более безопасный защитник на задней панели.

Ответ 4

Вопрос, который вам нужно задать самому, - кто несет ответственность за причинение ошибки в первую очередь?

Если это происходит в вашей системе, вы контролируете ее, просто допустите, чтобы ошибки попали вам, как обычно, и сорняли ошибки, когда вы идете вперед, но я подозреваю, что вы делаете приложение, которое сталкивается с реальными мировых пользователей, и вы хотите дезинформировать их ресурсы.

Я бы рекомендовал, чтобы клиентская сторона проверила правильность ввода, прежде чем отправить его на ваш сервер, и вы увидите хорошие вспомогательные сообщения, такие как "Ваше имя пользователя должно быть между символами x и y".

Затем на стороне сервера вы ожидаете, что в 99% случаев вход будет поступать непосредственно от вашего дезинфицирующего клиента, и поэтому вы все еще проверяете его с помощью тех методов, которые вы уже предложили, но если есть ошибка, вы просто возвращаете общее сообщение об ошибке для пользовательского интерфейса - поскольку вы доверяете, что ваш пользовательский интерфейс показал бы вспомогательные сообщения, поэтому ошибка проверки должна быть вызвана ошибкой или попыткой взлома.

Не забудьте зарегистрировать все ошибки проверки на стороне сервера, поскольку они могут быть серьезными ошибками или людьми, ищущими эксплойты.

Ответ 5

Предупреждение: Начиная с Mongoose 4.1.3 подпись для функции ValidatorError полностью изменилась, и приведенная ниже информация больше не применима:

В соответствии с Mongoose 3.8.12 сигнатура для функции ValidatorError:

function ValidatorError (path, msg, type, val) 

Если тип может быть либо "notvalid", либо "required"

Например, если в вашей проверке поля "электронная почта" возникает ошибка проверки, вы можете просто сделать:

var error = new ValidationError(this);
error.errors.email = 
      new ValidatorError('email', "Your err message.", 'notvalid', this.email);

Ответ 6

Как и в mongoose 4.5.0 Документ # invalidate возвращает ValidationError. Видеть это https://github.com/Automattic/mongoose/issues/3964

Кроме того, при попытке сделать недействительным на крюке запроса findOneAndUpdate вы можете сделать:

// pass null because there is no document instance
let err = new ValidationError(null)
err.errors[path] = new ValidatorError({
    path: 'postalCode',
    message: 'postalCode not supported on zones',
    type: 'notvalid',
    value,
})
throw(err)

Ответ 7

Смотрите пакет hmv, который поможет вам настроить шаблоны сообщений об ошибках mongoose, включая уникальные ошибки индекса:

template : {PATH_NAME} must be at least {MIN_LENGTH} characters long
schema   : { fullname : { type : String, min : 3, $name : 'Full name' } }
message  : Full name must be at least 3 characters long

template : {PATH_NAME} {VALUE} have been used, please choose another
schema   : { username : { type : String, unique : true } }
message  : username MrBean have been used, please choose another

И специально поддерживает локализацию, например на вьетнамском:

template : {PATH_NAME} dài ít nhất {MIN_LENGTH} kí tự
schema   : { fullname : { type : String, min : 3, $name : 'tên tài khoản' } }
message  : Tên tài khoản dài ít nhất 5 kí tự

Хорошим моментом является то, что вам нужно настроить шаблон сообщения только один раз, а не настраивать каждое поле каждой схемы в предыдущем подходе.