Any errors coming from the MongoDB driver API are passed to the callbacks as the first argument. Wrapping the calls in try/catch won't help you because the errors happen asynchronously. In other words, all your call to the MongoDB API does is begin an asynchronous operation, passing in a callback to be invoked later when the async operation is complete (your database call returns). If an error happens during the async operation, you won't be able to catch it with try/catch. Only the library itself will be able to catch those errors, which is why the library makes sure to pass them to your callbacks as the first argument.
collection.update({ a : 2 }, { $set: { b : 1 } }, function(err, result) {
if (err) { /* do error handling */ return; }
/* err is null, continue as normal */
});
If I were writing my own API that wraps some of these calls I'd do it one of three ways.
If the API I'm exposing is a callback-style API just like the MongoDB driver, then I'd do something like this.
exports.coolFunction = function (callback) {
collection.update({ a : 2 }, { $set: { b : 1 } }, function (err, result) {
if (err) { callback(err); return; }
callback(null, result);
};
Then someone could consume my API like this:
var alexLib = require('alexLibExample');
alexLib.coolFunction(function (err, result) {
if (err) { /* consumer handles error how they want to in their app */ }
/* all is good, no errors, continue normally */
});
Or I could make my API a promise-enabled API.
var Promise = require('bluebird');
exports.coolFunction = function () {
return new Promise(function (resolve, reject) {
collection.update({ a : 2 }, { $set: { b : 1 } }, function (err, result) {
if (err) { reject(err); return; }
resolve(result);
});
};
};
Then someone could consume my promise-enabled API like this:
var alexLib = require('alexLibExample');
alexLib.coolFunction().then(function (result) {
/* do stuff with result */
}).catch(function (err) {
/* handle error how user chooses in their app */
});
Or I could emit errors as an error event, which seems to be more what you're after.
var EventEmitter = require('events').EventEmitter;
exports.eventEmitter = new EventEmitter();
exports.coolFunction = function (callback) {
collection.update({ a : 2 }, { $set: { b : 1 } }, function (err, result) {
if (err) { exports.eventEmitter.emit('error', err); return; }
callback(result);
});
};
Then someone could consume my event-style API like this:
var alexLib = require('alexLibExample');
alexLib.eventEmitter.on('error', function (err) {
/* user handles error how they choose */
});
alexLib.coolFunction(function (result) {
/* do stuff with result */
});
The event style of API is usually combined with the callback style. Meaning they still pass errors to the callback functions, which is what most users expect when passing in callbacks. Then they also emit an error event as a sort of global error handler the user can subscribe to. I know this is the way Mongoose works. I can catch the errors on the individual API calls or I can setup an error event handler and handle all errors there.
var EventEmitter = require('events').EventEmitter;
exports.eventEmitter = new EventEmitter();
exports.coolFunction = function (callback) {
collection.update({ a : 2 }, { $set: { b : 1 } }, function (err, result) {
if (err) { exports.eventEmitter.emit('error', err); callback(err); return; }
callback(null, result);
});
};
Then the user has some flexibility with how they handle errors.
var alexLib = require('alexLibExample');
alexLib.eventEmitter.on('error', function (err) {
/* handle all errors here */
});
alexLib.coolFunction(function (err, result) {
if (err) { return; }
/* do stuff with result */
});
alexLib.coolFunction2(function (err, result) {
if (err) { /* maybe I have special error handling for this specific call. I can do that here */ }
/* do stuff with result */
});
If you really want to get fancy, you can combine all three styles.
var EventEmitter = require('events').EventEmitter;
var Promise = require('bluebird');
exports.eventEmitter = new EventEmitter();
exports.coolFunction = function (callback) {
return new Promise(function (resolve, reject) {
collection.update({ a : 2 }, { $set: { b : 1 } }, function(err, result) {
if (err) {
if (callback) { callback(err); }
reject(err);
exports.eventEmitter.emit('error', err);
}
if (callback) { callback(err, result); }
resolve(result);
});
});
};
Then someone could consume my API however they choose.
var alexLib = require('alexLibExample');
alexLib.eventEmitter.on('error', function (err) {
/* handle all errors here */
});
alexLib.coolFunction(function (err, result) {
if (err) {
/* handle this specific error how user chooses */
}
/* do stuff with result */
});
// or
alexLib.coolFunction().then(function (result) {
/* do stuff with result */
}).catch(function (err) {
/* handle any errors in this promise chain */
});