Declarative and simple IoC container for node.js applications
import { IoCContainer } from '@ukitgroup/ioc';
class ServiceA {}
// First of all you have to define DI config:
const moduleManifest = {
moduleName: 'module',
providers: [
{
isPublic: true,
token: 'serviceA',
useClass: ServiceA,
},
],
};
// Then in your composition root just create container
const container = new IoCContainer();
container.loadManifests([moduleManifest]);
container.compile();
You can provide by concrete realization with several ways:
class ServiceA {
constructor(serviceB) {
this.serviceB = serviceB;
}
}
// Dependencies will be resolved and injected to instance automatically
const providerByClass = {
token: 'serviceA',
useClass: ServiceA,
dependencies: ['ServiceB']
};
// You can provide constant value
const providerByValue = {
token: 'connectionUri',
useValue: 'mongodb://uri',
};
// You can provide by factory function
// Also resolved dependencies will be resolved automatically
const providerByFactory = {
token: 'ServiceA',
useFactory: (serviceB) => {
return new ServiceA(serviceB)
},
dependencies: ['ServiceB']
};
By default all providers define in private
scope.
If you want to use provider from another module you should define this provider as public
const moduleAManifest = {
moduleName: 'moduleA',
providers: [
{
isPublic: true,
token: 'ServiceA',
useClass: ServiceA,
},
],
};
const moduleBManifest = {
moduleName: 'moduleB',
providers: [
{
isPublic: true,
token: 'ServiceC',
useClass: ServiceC,
dependencies: [
// You should define which module this provider from
['ServiceA', { fromModule: 'moduleA' }],
],
},
],
};
There are some cases when you want create instances in code i.e: Entities, Command pattern
It's very simple if your class doesn't have dependencies so you can create instance just in you code:
class Entity {
constructor(name) {
this.name = name;
}
}
class Example {
doSomething() {
const a = new Entity('test');
// ...
}
}
But there are some cases when this class has dependencies and you can't just create object because you have to transmit resolved provider.
Fortunately we are codding with Javascript
and so we can follow js way
:)
class Entity {
constructor(service, name) {
this.service = service;
this.name = name;
}
}
class Example {
// You can inject Constructor with resolved dependencies
constructor(Entity) {
this.Entity = Entity;
}
doSomething() {
// Now you still have to provide rest arguments
// And all dependencies has already resolved
const a = new this.Entity('test');
// ...
}
}
// Of course there are some config parameters to make this magic work :)
const moduleManifest = {
moduleName: 'moduleB',
providers: [
{
isPublic: true,
token: 'Entity',
useClass: Entity,
dependencies: [
// You should define which module this provider from
['ServiceA', { autoFactory: true }],
],
},
{
token: 'ServiceA',
// To make it clear you should define in both "autoFactory: true"
autoFactory: true,
useClass: ServiceA,
}
],
}
Usually you have composition root in you application.
It's the only place where you can use container.get
const moduleManifest = {
moduleName: 'moduleA',
providers: [
//... other providers
{
isPublic: true,
token: 'httpPort',
useValue: 3000,
},
],
};
const container = new IoCContainer();
container.loadManifests([moduleManifest]);
container.compile();
// You can get only public providers
const port = container.get('moduleA', 'httpPort');
http.listen(port);
We provide a comfortable way for testing
import { TestIoCContainer } from '@ukitgroup/ioc';
describe('Unit test', () => {
const ctx = {}
beforeEach(() => {
ctx.container = TestIoCContainer.createTestModule([
//... providers definition with mocks
])
ctx.container.compile();
});
it('test case', () => {
// Here you can just get provider by token
// You don't have to transmit module name
const provider = ctx.container.get('providerToken');
});
})
if you don't use typescript, type hinting
still can help you:
Just be sure that you use type definitions only from ./public-interfaces
.
Internal types can be changed not in major release
More examples you can find in integration tests
- support decorators with typescript
- TestIoCContainer for integration tests
- Get public providers by tag