A simple "promiseful" node.js DI:
- Write services as factory functions, one service per file
- Create a pdi-js instance by specifying the directory where your services are.
- Use the pdi-js to get a service instance (the result of a factory function) by specifying the path of your service (where the root implicitely is the directory we talked about previously)
- A pdi-js instance can be created with a "suffix" : only files with this suffix will be considered as service factory
- Once a pdi-js instance is created, anything can be added to it and later be retrieved as a service
$ npm install pdi-js --save
When the service files are located in a dedicated directory, it's convenient to use pdi-js without suffix:
const PDI = require('pdi-js');
/////////////////////
// create a new di //
/////////////////////
// the argument used for construction points to your service directory
const myServiceDirectory = __dirname + '/services';
var pdi = new PDI(myServiceDirectory);
///////////////////////////////
// get a service from a file //
///////////////////////////////
// will use the service file {your service directory}/bar.js
pdi.get('bar').then(bar => {
// bar is the result of the service factory described in {your service directory}/bar.js
});
// will use the service file {your service directory}/foo/bar.js
pdi.get('foo/bar').then(bar => {
// bar is the result of the service factory described in {your service directory}/foo/bar.js
});
// will use the files {your service directory}/bar.js and {your service directory}/foo/bar.js
pdi.get(['bar', 'foo/bar']).then([bar, fooBar] => {
// bar is the result of the service factory described in {your service directory}/bar.js
// fooBar is the result of the service factory described in {your service directory}/foo/bar.js
});
// will use the files {your service directory}/bar.js and {your service directory}/foo/bar.js
pdi.get({
bar: 'bar',
fooBar: 'foo/bar'
}).then({bar, fooBar} => {
// bar is the result of the service factory described in {your service directory}/bar.js
// fooBar is the result of the service factory described in {your service directory}/foo/bar.js
});
When the service files are mixed up with other files, just use a suffix, pdi-js will ignore all unsuffixed files.
const PDI = require('pdi-js');
/////////////////////
// create a new di //
/////////////////////
// Let's say your services are mixed up with other files.
// You have to construct a pdi-js instance pointing to your souce directory.
const mySourceDirectory = __dirname;
// Now, we choose a suffix for our service files
const mySuffix = '.srv';
var pdi = new PDI(mySourceDirectory, mySuffix);
///////////////////////////////
// get a service from a file //
///////////////////////////////
// will use the service file {your source directory}/bar.srv.js
pdi.get('bar').then(bar => {
// bar is the result of the service factory described in {your source directory}/bar.srv.js
});
// will use the service file {your source directory}/foo/bar.srv.js
pdi.get('foo/bar').then(bar => {
// bar is the result of the service factory described in {your source directory}/foo/bar.srv.js
});
// will use the files {your source directory}/bar.srv.js and {your source directory}/foo/bar.srv.js
pdi.get(['bar', 'foo/bar']).then([bar, fooBar] => {
// bar is the result of the service factory described in {your source directory}/bar.srv.js
// fooBar is the result of the service factory described in {your source directory}/foo/bar.srv.js
});
// will use the files {your source directory}/bar.srv.js and {your source directory}/foo/bar.srv.js
pdi.get({
bar: 'bar',
fooBar: 'foo/bar'
}).then({bar, fooBar} => {
// bar is the result of the service factory described in {your source directory}/bar.srv.js
// fooBar is the result of the service factory described in {your source directory}/foo/bar.srv.js
});
A PDI instance can also be "stored" then be used "statically":
const PDI = require('pdi-js');
const pdi = new PDI(`${__dirname}service/directory`);
PDI.setStaticDi(pdi);
// Later, in some other file...
const PDI = require('pdi-js');
PDI.get('bar').then(bar => {});
PDI.clear(); // the PDI instance is not stored anymore (useful for unit testing)
The services are node.js modules that simply returns a factory function :
// {your service directory}/random.js
const random = () => {
return Math.floor(Math.random() * 1000);
};
module.exports = random
// {your service directory}/foo.js
const foo = () => {
return 'foo';
};
foo.cache = true; // the result of this service factory function will be cached by PDI
module.exports = foo
Other services can be used as dependencies for your factory function:
// {your service directory}/baz.js
const bar = ([foo, fooBar]) => {
return 'bar';
};
bar.dependencies = ['foo', 'foo/bar'];
module.exports = bar
// {your service directory}/baz.js
const bar = ({foo, fooBar}) => {
return 'bar';
};
bar.dependencies = {
foo: 'foo',
fooBar: 'foo/bar'
};
module.exports = bar
Eventually, you can directly pass a service instance to the pdi, it will be "stored" as a cached service:
const someService = {name: 'some service'};
pdi.set('some/service', someService);
pdi.get('some/service').then(service => {
// service === someService
});
A composition is just a plain old javascript object describing a list of dependency free services. It's usefull when we want to initialize several services that will be later used as dependecies. A composition is usually used at the initialization time of an application, and get busy with stuff like db configuration/connection.
const composition = {
dbConnection: new Promise((resolve) => {
const dbConnection = // do stuff here to get a db connection
resolve(dbConnection);
}),
iceCreamFactory: (flavour) => ({ flavour })
};
pdi.executeComposition(composition)
.then(() => {
// ...
});
// Now, the services "dbConnection" and "iceCreamFactory" can be used as dependencies or retrived by inversion of control
pdi.get(['dbConnection', 'iceCreamFactory'])
.then(([dbConnection, iceCreamFactory]) => {
const myIceCream = iceCreamFactory('strawberry');
return dbConnection.executeRequest(/* whatever is needed to save myIceCream into that db */);
});