Cation
A fast and customizable Dependency Injection Container
for Node.js / io.js
var Cation = var container = var { /* Atom service! */ } container container
Brief intro
Cation is a powerful Dependency Injection Container (DIC). The first version was released in 2011-2012 as an unstable/experimental library and was inspired by the Symfony 2 container. It only allowed a JSON schema to register a service (yeah, it was an ugly experiment). There were no Factories, no Decorators. Just "Services".
The version 2 is a MUCH, MUCH BETTER EVOLUTION, heavily inspired by these projects:
- Symfony DIC - API
- Dependency Injection: the Ember.js way - API
- Dependency Injection: the Angular.js way - API
Cool things you'll enjoy for sure:
- Organize all your dependencies in a single place. Retrieve them only when you need them.
Service
,Factory
andStatic
resource providers, right out of the box.Decorator
support.- User-defined / Custom resource providers.
- Lazy loaded dependencies (and it's awesome).
- Future-proof JavaScript / ES6 support.
- Beautiful API.
Installation
$ npm install cation
Usage
Services
Simple Services
This is probably one of those things you are doing a lot, creating new objects. I'm going to reuse the Atom
example from the top of this file and explain with simple words what happens when you use Cation.
This is the constructor for a service object:
var { /* Atom constructor */ }
And this is how you register the Atom constructor in the container:
var Cation = var container = container
Boom. It's done. If you need a new object:
container // or... var getAtomPromise = container getAtomPromise
So, what happened here?
- You call
Cation#register
. - Cation creates a new
ServiceProvider
object with the arguments you provided. - Cation stores the provider object in an internal repository.
- Done with the register process.
- Now you call
Cation#get
. - Cation returns a new
Promise
object. - You call
Promise#then
and pass a callback function that will be executed when the promise is resolved. - In the meantime, Cation looks in the repository for the desired provider.
- Cation asks the provider to digest the original arguments and to return something.
- The
ServiceProvider
internally creates a new object from the constructor function you provided in the first place and returns it. - Cation resolves the previous promise with the object returned by the provider.
- You have your service object.
Dependency Injection
The main purpose of a Dependency Injection Container. Imagine you need to create a chemical element object, with a few arguments:
var { thisname = name thissymbol = symbol thisatomicNumber = atomicNumber thisatomicWeight = atomicWeight} container container
What if one or more arguments are dependencies to other services? Let's take a look at a little more complex example:
// HEADS UP!//// For the sake of "simplicity", I'm going to use a few ES6 features in this example.//// The third argument here, ...elements, is known as a "rest parameter" and is part of the ES6 specification.// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parametersvar { thisname = name thisformula = formula thiselements = elements this { // HEADS UP! // I'm using "arrow functions" here. It's also part of ES6. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions return thiselements }} container container // This. Read it carefully...container container
Sweet, isn't it? Just remember: you can use whatever you want as an argument. But if you need an argument that is a registered resource in Cation, you need to reference it by using a string like "@MyRegisteredResource".
Q: What if I need, in fact, an argument that is a string and starts with the @
character but it's not a resource reference?
A: You can escape it with double backslashes.
container
By doing this, your service will receive a new ServiceReference object as a first argument and "@NormalStringArgument" as a second argument.
Psst! Click here to see this example using ES6 syntax.
Singletons
Enabling this pattern is as easy as setting an option named singleton
to true
.
container
register
options
A note about Service As you can see, the register
method can take up to three arguments:
- id: resource identifier.
- resource: the resource to be registered (in this case, the service constructor).
- options: an object containing options.
When you are registering a service
, the available options are:
type
: this option is always provided by default asservice
. You can replace it withtype: 'factory'
and you'll be registering a factory, instead of a service. You'll learn about this in the next topic.singleton
: boolean option andfalse
by default. If set to true, Cation will treat the resource as a singleton.args
: array option,[]
by default. These are the arguments to apply to the service constructor. It only works if thetype
isservice
.decorators
: array option,[]
by default. These are the names of theDecorators
to be applied to the returned objects. You'll learn about this in theDecorators
topic.tags
: array option,[]
by default. You can use this feature to tag your services. You'll learn about this inWorking with tagged resources
section.
Having known that, these options are the same:
type : 'service' singleton : true args : 'a' 2 '@B' decorators : 'decorator1' 'decorator2' singleton : true args : 'a' 2 '@B' decorators : 'decorator1' 'decorator2'
args : singleton : true singleton: true
Factories
If you need a more granular control over your created objects, you can opt for the Factory Pattern. In Cation, a factory must follow these simple rules:
- The factory function receives the container object as an optional argument. Useful only if you need dependencies from it.
- The factory function must return a Promise.
- The
Cation#register
method must receive anoptions
object with, at least, a propertytype
equals tofactory
.
// if you know how promises work, you'll notice that this code block can be// simpliflied by just returning the execution of Promise.all().then().// I'll keep this example to explicitly show the returned promise.container container
// and this is the simplified version of the above implementationcontainer container
Options
The Cation#register
method, when registering a factory resource, can take these options:
type
: you MUST set this option to'factory'
.singleton
: boolean option,false
by default. After the first factory execution, the instance will be stored as a singleton.decorators
: array option,[]
by default. These are the names of theDecorators
to be applied to the returned objects. You'll learn about this in theDecorators
topic.tags
: array option,[]
by default. You can use this feature to tag your factories. You'll learn about this inWorking with tagged resources
section.
Psst! Click here to see this example using ES6 syntax.
Static resources
These kind of resources are treated as constants by Cation. You can freely register a number, string, array, object or functions. Every time you call Cation#get
you'll receive the same value.
// register a static resourcecontainer // use the resource as a dependency in a servicecontainer
Options
type
: you MUST set this option to'static'
.tags
: array option,[]
by default. You can use this feature to tag your resources. You'll learn about this inWorking with tagged resources
section.
Decorators
The Cation decorators are simple functions called just after the service creation, but before it's returned to you. Its main purpose is to decorate a given object. Every decorator must follow these rules:
- The decorator function must receive the object to decorate, as an argument.
- The decorator function must return the same object or another one that supersedes it.
- The
Cation#register
method must receive anoptions
object with, at least, a propertydecorators
equals to an array with the decorator names to be applied.
// Example inspired by "Learning JavaScript Design Patterns" book by Addy Osmani { this { return 13 } this { return 128 } this { return '2.6GHz dual-core Intel Core i5' } this { return 1299 } this { return '%in%-inch MacBook Pro with Retina Display. Storage: %storage%GB. CPU: %cpu%. Price: $%price%.' }} container container // 128GB storage versioncontainer // 256GB storage versioncontainer // 512GB storage + higher freq CPUcontainer // ---- container container container
Custom Resource Providers
Every time you call Cation#register
and, in the options object, you specify a type
, what you are really doing is telling Cation to use an specific Resource Provider
.
As you can clearly see now, Cation comes with three Providers by default:
ServiceProvider
. { type: 'service' }FactoryProvider
. { type: 'factory' }StaticProvider
. { type: 'static' }
What if, for some reason, you need a custom provider?
/** * The GhostProvider will register a new static resource every time you * register something using this type. * Also, it provides a "Boo! 👻" string when trying to retrieve the registered resource. * * @param * @param * @param * @param */ { // All ResourceProviders are created with these args, always. thiscontainer = container thisid = id thisresource = resource thisoptions = options thiscontainer // This is where magic happens... // You must ALWAYS implement a `get` method. this { // And this method should ALWAYS return a new Promise. return { // NEVER forget to resolve the promise with whatever you want to return on `Cation#get`. Never. } }} container container // and here... we... GO. container
Psst! Click here to see this example using ES6 syntax.
Identifying every container instance
The Cation constructor can take an options object as an argument. Currently, the only supported option is id
. With this ID you can keep track of your containers, in case you are creating more than one.
var container1 = id: 'c-1' var container2 = id: 'c-2' console // c-1console // c-2
Working with tagged resources
Tags are strings that can be applied to any resource. By themselves, tags don't actually alter the functionality of your resources in any way, but can be really useful if you need to group them to easily retrieve and manipulate them in some specific way.
To enable this feature, just register a resource with an option tags
equals to an array of strings.
// https://github.com/wycats/handlebars.jscontainer { this { var template = Handlebars return }} container // somewhere,// in your awesome new JS framework... var compilerId = container container // now, if you want another compiler // https://github.com/paularmstrong/swigcontainer { this { return Swig }} container // you can do really cool things with this new feature. A little more complex example// could have been loading all tagged compilers and make them compile .hbs or// .swig templates, with just one function:// container.get(compilerId).then(function(compiler) { ... }) // just go and make awesome things :)
Contributing
Please, check the Contributing.md document for detailed info.
ES6 Examples (WIP)
License
Check the LICENSE file.
API
Cation(options)
Cation constructor
Parameters | Type | Description |
---|---|---|
options (optional) |
object | An object containing options. |
Options
Name | Type | Description |
---|---|---|
id (optional) |
string | An ID for the current Cation instance. |
Cation.prototype.getId()
Return
Type | Description |
---|---|
string | The container ID. |
Cation.prototype.register(id, resource, options)
Registers a service constructor, a factory function or a static value.
Parameters | Type | Description |
---|---|---|
id | string | The ID of the resource to register. Must be unique. |
resource | mixed | The resource to be registered. |
options (optional) |
object | An object containing options. |
Options
Name | Type | Description |
---|---|---|
type (optional) |
string | Specify the type of resource to be registered. It can be service (default), factory or static. |
args (optional) |
array | Arguments to apply if the registered resource is a service. |
singleton (optional) |
boolean | Singleton behaviour. |
decorators (optional) |
array | Decorators to be applied to the returned instances. |
Cation.prototype.get(id)
Retrieves a resource from the container.
Parameters | Type | Description |
---|---|---|
id | string | The ID of a previously registered resource. |
Return
Type | Description |
---|---|
Promise | Promise whose resolved value is the requested service instance / resource value. |
Cation.prototype.has(id)
Checks if a resource is registered.
Parameters | Type | Description |
---|---|---|
id | string | The ID of a resource. |
Return
Type | Description |
---|---|
Boolean | true if the container has the resource, false otherwise. |
Cation.prototype.remove(id)
Removes a resource from the container.
Parameters | Type | Description |
---|---|---|
id | string | The ID of a resource. |
Cation.prototype.addProvider(name, providerFunction)
Registers a resource provider.
Parameters | Type | Description |
---|---|---|
name | string | Provider name. Must be unique. |
providerFunction | function | Provider function. |
providerFunction
Parameters | Type | Description |
---|---|---|
container | Cation | A Cation instance. |
id | string | The ID of the resource being registered. |
resource | mixed | The resource being registered. |
options | object | An object containing options. |
Cation.prototype.hasProvider(name)
Checks if a given provider is registered.
Parameters | Type | Description |
---|---|---|
name | string | The name of a provider. |
Return
Type | Description |
---|---|
Boolean | true if the container has the provider, false otherwise. |
Cation.prototype.removeProvider(name)
Removes a given provider.
Parameters | Type | Description |
---|---|---|
name | string | The name of a provider. |
Cation.prototype.addDecorator(name, decoratorFunction)
Registers a resource decorator.
Parameters | Type | Description |
---|---|---|
name | string | Decorator name. Must be unique. |
decoratorFunction | function | Decorator function. |
decoratorFunction
Parameters | Type | Description |
---|---|---|
resource | mixed | The resource to be decorated. |
Cation.prototype.hasDecorator(name)
Checks if a given decorator is registered.
Parameters | Type | Description |
---|---|---|
name | string | The name of a decorator. |
Return
Type | Description |
---|---|
Boolean | true if the container has the decorator, false otherwise. |
Cation.prototype.removeDecorator(name)
Removes a given decorator.
Parameters | Type | Description |
---|---|---|
name | string | The name of a decorator. |
Cation.prototype.isCached(id)
Checks if a resource is cached. Only instances from services declared as singleton
will be stored in cache.
Parameters | Type | Description |
---|---|---|
id | string | The ID of a resource. |
Return
Type | Description |
---|---|
Boolean | true if the container has the resource in the singleton cache, false otherwise. |
Cation.prototype.clearCache()
Removes all singleton instances from cache.
Cation.prototype.findTaggedResourceIds(tagName)
Returns an array of resource IDs for a given tag.
Parameters | Type | Description |
---|---|---|
tagName | string | The tag name. |
Return
Type | Description |
---|---|
Array | An array of resource IDs. |