Правильная обработка ошибок выборки для Mongoose?

Это чистый вопрос о лучшей практике. Я новичок в Node и Mongoose. Мне очень нравится эта технология, и я запускаю проект по созданию API на основе JSON для приложения, которое я создаю.

Я обнаружил, что постоянно повторяю код, когда извлекаю объекты из своей базы данных. Например:

Playlist.findById(req.params.id, function(err,playlist){
  if (err)
    return res.json({error: "Error fetching playlist"});
  else if (!playlist)
    return res.json({error: "Error finding the playlist"});

  //Actual code being performed on the playlist that I'm fetching
});

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

Я думал об использовании обратного вызова, например:

var fetchCallback = function(err,objOrDoc,callback){
  //Handle the error messages
  callback(objOrDoc);
};

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

Мне интересно, сталкивался ли кто-нибудь с этой проблемой и есть ли какие-либо рекомендации по сокращению повторения.

Я также использую экспресс-фреймворк, поэтому, если есть полезный способ справиться с ним в экспрессе, мне тоже было бы интересно узнать.


person Michael D.    schedule 06.05.2012    source источник


Ответы (1)


Здесь можно попробовать несколько интересных подходов.

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

fetchResource = function(model, req, res, callback) {
  model.findById(req.params.id, function(err, resource) {
    if (err)
      return res.json({error: "Error fetching " + model.toString()});
    else if (!playlist)
      return res.json({error: "Error finding the " + model.toString()});

    callback(resource);
  });
};

app.on('/playlists/1', function(req, res) {
  fetchResource(Playlist, req, res, function(playlist) {
    // code to deal with playlist.
  });
});

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

ПО промежуточного слоя маршрутизации

Маршруты могут использовать промежуточное программное обеспечение для конкретного маршрута, передавая методу один или несколько дополнительных обратных вызовов (или массивов). Эта функция чрезвычайно полезна для ограничения доступа, загрузки данных, используемых маршрутом, и т. д.

Я не проверял это, и это немного ручная работа (читай: псевдокод), но я думаю, что это должно служить достойным примером.

// assuming a URL of '/playlist/5' or '/user/10/edit', etc.

function loadResource(model) {
  return function(req, res, next) {
    model.findById(req.params.id, function(err, resource) {
      if (err)
        return res.json({error: "Error fetching " + model.toString()});
      else if (!resource)
        return res.json({error: "Error finding the " + model.toString()});

      req.resource = resource;
      next();
    });
  }
}

app.get('/playlist/:id', loadResource(Playlist), function(req, res) {
  var playlist = req.resource;
  ...
});

app.get('/user/:id', loadResource(User), function(req, res) {
  var user = req.resource;
  ...
});

Исходный код содержит довольно хороший пример этого шаблона, а в разделе промежуточное ПО в документации (в частности, в разделе "Промежуточное ПО маршрутизации") .

person Michelle Tilley    schedule 06.05.2012
comment
Это фантастический ответ. Спасибо за вашу помощь в этом! - person Michael D.; 08.05.2012
comment
Рад, что помог! Удачи! ^_^ - person Michelle Tilley; 08.05.2012
comment
Спасибо, отлично; ссылки в конце вашего ответа, к сожалению, больше не действительны. - person Stefan Walther; 14.10.2014