Using module.exports the “right way” for service instances and IDE introspection

I’m using service objects in node.js that are responsible for database operations on business entities and also perform some kind of  low level business logic if needed. Recently I was refactoring my code and came up with this pattern which I currently consider a “best practice” of doing things.

Service Objects that should perform asynchronous actions on remote services like querying a database  must get their resources at some point. Naively you could instantiate each service every time you need it, provide them a (fresh) link to your database (that you might want to store globally or in an application instance that you’re handing around). Now, in Javascript, respectively in a node.js / CommonJS environment there’s a better way of doing that: the module. It is not too obvious for developers coming from a Java-like background that those modules can (but don’t have to) be used for instantiating “singleton” services and can deal as single activation points to set your service objects up with their resources. So here’s an example (please note that I’m omitting some “real world” db logic, the mongo connection is there only for illustration):

Your “service module”, responsible of getting a user from a database (“UserService.js”)


var UserService = function() {

this.db = null;
this.collectionName = "users";
this.collection = null;

}

UserService.prototype = {

connect: function(db) {
if (this.db != null)
return;

this.db = db;
this.collection = db.collection(this.collectionName);
}

getUser: function(id, callback) {
this.db.findOne({_id:id}, callback);
}

}

module.exports.UserService = new UserService();

Your main module (“app.js” or whatever you want to call it)


var db = require('mongojs'),
UserService = require('service').UserService

db.connect("mongodb://a-fancy-server:27109/master");

app.set('mngdb', db);
UserService.connect(db);
var xId = new mongoSkin.ObjectID("1a2b3c4b5e...");
UserService.getUser( xId, function(err, doc) {
console.dir(doc);
}

Notice that you’re initializing (“connecting” in this case) the single instance of UserService in your main module. That means that it is ready to go in any other module where you would like to use it. That’s a good solution for immutable service instances that don’t depend on any state but only on some resources like database connections or global settings.

In the rare case where you’d like to have another user service you could export the constructor from your service module as well (in UserService.js)


...
module.exports._UserService = UserService;

and if you need another one, you can (anotherModule.js):

var db = require('mongojs').connect("mongodb://a-crazy-server:27110/samples");
var myCustomUserService = new require('UserService')._UserService();
myCustomUserService.connect(db);

There’s one little twist that I found when playing around that might be helpful when you try this “pattern” on your own. You might be tempted to omit the service’s name in the module.export like so (UserService.js):

....
//don't do that
module.exports = new UserService();

because then you could (yetAnotherModule.js):

var userService = require('UserService');
userService.getUser(...)

That code is definitely working. But note, that you a) cannot export anything else (e.g. the constructor) now  and b) your IDE might not be able to resolve the methods (getUser) of that instance (e.g. IntelliJ WebStorm cannot).

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s