A lightweight dependency injection container for Node.js.
This library currently supports Node.js >= 8.0.0.
To be honest dependency injection isn't really necessary in Node.js most of the time due to its module-based design but I created this library because I wanted the following.
- A lightweight container that I can instantiate on every HTTP request
- Lazy-loaded services that only get instantiated if they're used
- The ability to decouple modules for testing without needing
proxyquire
- Eliminate relative paths to other modules
This library is intended for use in Node.js projects and can be installed with npm
.
npm install fast-inject --save
Containers are merely just an object with properties for constants or services. These constants or services are provided as singletons. Services are also lazy-loaded and thus only get instantiated if they are accessed.
To setup a container you just create an Injector
instance and register your constants and/or services.
const { Injector } = require('fast-inject');
// Service class
class B {
// Expects an instance of `A` to be injected.
constructor(a) {
this.a = a;
}
}
// Service class
class C {
// Expects an instance of `B` to be injected.
constructor(b) {
this.b = b;
}
}
const { container } = new Injector()
// Constants can provide any static value (string, number, Object, Function).
.constant('A', 1234)
// Services must be defined as ES6 classes and can have dependencies.
// Any dependencies are injected into the constructor when the service is instantiated.
.service(B, ['A'])
// Use the `name` property of the class when one service is dependent on another.
.service(C, [B.name]);
// Access a constant
console.log(container.A);
// 1234
// Access a service
console.log(container.B.a);
// 1234
// Access a nested service
console.log(container.C.b.a);
// 1234
In addition to using the approach above, fast-inject
also allows you to build a container
pipeline by means of functional composition. Ramda
is used in the example below but you can
use any library that supports function composition like Lodash
or Underscore.js
.
const R = require('ramda');
const { constant, service } = require('fast-inject');
// Service class
class B {
// Expects an instance of `A` to be injected.
constructor(a) {
this.a = a;
}
}
// Service class
class C {
// Expects an instance of `B` to be injected.
constructor(b) {
this.b = b;
}
}
// Compose the pipeline
const pipeline = R.pipe(
constant('A', 1234),
service(B, ['A']),
service(C, [B.name])
);
// Create a container
const container = pipeline(Object.create(null));
The functional approach also gives you the advantage of being able to compose multiple pipelines together.
- constant(name, value, container) ⇒
Object
Define a constant on a container.
- service(Class, dependencies, container) ⇒
Object
Define a service on a container.
Kind: global class
Properties
Name | Type | Description |
---|---|---|
container | Object |
The container instance. |
The class for constructing a dependency container.
injector.constant(name, value) ⇒ Injector
Define a constant on the injector's container.
Kind: instance method of Injector
Returns: Injector
- The Injector instance.
Param | Type |
---|---|
name | string |
value | * |
injector.service(Class, dependencies) ⇒ Injector
Define a service on the injector's container.
Kind: instance method of Injector
Returns: Injector
- The Injector instance.
Param | Type |
---|---|
Class | function |
dependencies | Array.<string> |
Define a constant on a container.
Kind: global function
Returns: Object
- The container instance.
Param | Type |
---|---|
name | string |
value | * |
container | Object |
Define a service on a container.
Kind: global function
Returns: Object
- The container instance.
Param | Type |
---|---|
Class | function |
dependencies | Array.<string> |
container | Object |