I am creating a module dependent on another async one. I'm trying to find the best way to expose my module so that the developer using it finds it intuitive.
Initially my module looked something like this:
var soap = require('soap');
var service = {};
soap.createClient('http://mysoapservice', function(err, client){
service.myMethod = function(obj, callback){
//dependency on soap module
client.soapMethod(obj, function(err, data){
//do something with the response
//call other methods etc...
var res = "processed "+data['name'];
callback(err, res);
});
};
});
module.exports = service;
Of course the problem here is that calling mymethod before the callback inside the module code is reached will throw an exception.
What would be the best pattern to use for such a module?
Is returning promises specific to other libraries (q) an acceptable scenario? or should I just return a callback for when the module is initialized and let the developer handle the rest?
Firstly, I would not use singleton pattern. What if the user wants more than one service? It's better to have a constructor or a factory for this. This provides more design flexibility and makes things clearer for the user. For example:
// constructor
var Service = function() {
this.initialized = false; // service is not initialized
};
Service.prototype.myMethod = function(...) {
// check if initialized
if (!this.initialized)
return false;
// do your stuff here
...
};
Service.prototype.initialize = function(..., cb) {
// do your initialization and call the callback
// also, set this.initialized to true
};
// want to have a factory, to provide a "createService" function?
// no problem
Service.createService = function(..., cb) {
var service = new Service();
service.initialize(..., cb);
// service will only be usable once initialized, but the user
// can still store a reference to the created object to use
// in his callback
return service;
};
module.exports = Service;
Use it like this:
// constructor + initializer
var myService = new Service();
service.initialize(..., function(...) {
// we have the service, do stuff:
myService.myMethod(...);
});
// factory method
var myService = Service.createService(..., function(...) {
// we have the service, do stuff
myService.myMethod(...);
});
In both cases, calling myMethod() before init will merely return false (instead of throwing).
I like this pattern because it's very similar to other patterns of popular modules out there, so users are used to it and know what to expect.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With