The error that is thrown towards the end of this example should probably be passed back to the callback as an argument (e.g. callback(error, result)) instead.
I was debating whether or not to put it in there. Since Isaac mentions it in his article that I link to, I figured most people would see it there. Very valid point though. I think I may edit the post and put it up there. Thanks!
I liked the part where you encouraged the developer to think about how the API will be consumed by the end user; however even a brief mention of some BDD / Unit tests here would have been nice (:
Slightly OT: does anyone have a good explanation for module.exports vs exports and for the expression 'exports = module.exports = someFunction' often found in modules?
Whatever module.exports is at the end of the module is passed to the require statement.
Every file essentially has two lines at the top.
this = module.exports;
var exports = module.exports;
The first helps lazy developers by allowing exporting without explicitly saying so. Because of this, the following alone is a valid module that exports {foo:'bar'}
foo = 'bar'; // can also be written as this.foo = 'bar';
And the second matches the CommonJS standard. So the following CommonJS module will work:
exports.foo = 'bar';
If you assign module.exports at any time after using `this` or `exports`, module.exports will point to the new object, and anything on the original module.exports object wont be passed to the `require` call.
Reassigning the `exports` variable does not change the return value of `require`.
The return value of `require` is `module.exports`, which may be reassigned.
Initially, the global `exports` variable is set to the same value as `module.exports`. Writing `exports = module.exports = ...` ensures they have the same value as you would expect.
'this' is also the same as exports. Initially, they all have the same value, they all point at the same object. If you assign module.exports to a new object (vs simply adding properties to the existing object) it will ignore the value of exports and this.
It's incredibly confusing and they should have just picked one way to export data, instead of three.
So you reassigned module.exports to exports in order to get all objects assigned to both module.exports and exports otherwise objects assigned to module.exports would override those assigned to exports which would stay ignored, right?
But: to get all objects do I have to assign module.exports to exports (so change the order from your first example)?:
I usually use just `module.export = {...}` in the bottom line when I want to export object by object literal.
To be honest, I'm not quite sure about commonJS require implementation of nodeJS. But as long as I'm understand,
1. Use `module.exports` if you want to assign exports by object literal
2. Use `exports.[key]` if you want to assign exports brick by brick.
3. Use `exports = module.exports = {...}` or `module.exports = exports` if you want to ensure both functionality; you can assign `exports.[key] after assign exports by object literal.
Not that I've experienced. Another cool trick: modules make sense when you use packages, but they feel like PHP 4 when you just try to divide your code to several files.
This fixes part of the problem, but what happens when you reference './models/user.js' from the file 'auth.js' but then auth grows in size and you decide to divide it and put it in auth/facebook.js, auth/twitter.js, etc. -- well, now you are fucked.
This gives you the flexibility to transparently change the file into a folder + index.*, then break functionality up into pieces that live inside that folder.
Throwing errors in an asynchronous context can have messy results for trying to handle them. http://benno.id.au/blog/2011/08/08/nodejs-exceptions is a good explanation.