Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js, Express and Dependency Injection

I'm in early stages of a node.js project, and I'm looking to improve the overall app organization. In the past I worked with Symfony2 (PHP) and now I code a lot in Angular, both of which relly heavily on DI. So, I really like the idea of applying the same principles in my node.js project.

I know the existence of packages like Rewire, but for now I'll like to try the DI approach. The issue is, how to achieve an equilibrium to keep the lightweight feeling that gives working with node with the solidity of a well tested dependency injected app (I know that well tested is what gives the solidity ;-)).

Node modules

One of the issues, would be how to manage the external modules, what to do if some object needs fs module? As Vojta Jina (from AngularJS) states in this article:

So the best way that works for me right now is something like this: Modules are stateless. They only contain definitions of classes/functions/constants.

So, I suppose that I would have to inject everything:

function Foo(fs) {
    this.fs = fs;
}

Foo.prototype.doSomething: function () {
    // this.fs...
};

module.exports = Foo;

Somewhere:

var fs  = require('fs');
var Foo = require('./Foo');
var foo = new Foo(fs);

foo.doSomething();

Express

Since Express uses apply() to call the handlers the context is lost and we can't use this. So we're left with these:

// foo.js
function Foo(fs) {
    this.fs = fs;
}

Foo.prototype.index = function () {
    var self = this;

    return function (req, res, next) {
        // self.fs...
    };
};

module.exports = Foo;

// bar.js
module.exports.index = function (fs) {
    return function (req, res, next) {
        // fs...
    };
};

// app.js
var express = require('express');
var fs      = require('fs');
var app     = express();
var Foo     = require('./foo');
var foo     = new Foo(fs);
var bar     = require('./bar');

app.get('/foo', foo.index());
app.get('/bar', bar.index(fs));

So...

Has someone taken this approach? What about the use of DI frameworks? (like di.js) And how to keep the experience lean? All ideas are welcome. Thanks!

like image 399
doup Avatar asked Jul 02 '14 10:07

doup


People also ask

Does NodeJS have dependency injection?

In short, you don't need a dependency injection container or service locater like you would in C#/Java. Since Node. js, leverages the module pattern , it's not necessary to perform constructor or property injection.

What is the difference between NodeJS and Express?

NodeJS is an event-driven, non-blocking I/O model using JavaScript as its main language. It helps to build scalable network applications. Express is a minimal and flexible Node. js web application framework that provides a robust set of features for web and mobile applications.

What is dependency injection Express?

Express makes it very easy to inject dependencies into you web application through middleware or into individual routes. In my Express applications when I need a dependency, I inject it directly into a route by injecting it as a service on the request object.

What is Express () in NodeJS?

Express is a node js web application framework that provides broad features for building web and mobile applications. It is used to build a single page, multipage, and hybrid web application. It's a layer built on the top of the Node js that helps manage servers and routes.


2 Answers

You have some good thoughts to which I'd like to add:

  • Having stateless modules will help you to scale your app horizontally. If all state is in a database it will be easy to run multiple node.js instances in parallel.
  • I also prefer to inject everything. Otherwise the time will come when I would like to write a unit test and it gets hard because I have a hardcoded (not injected) dependencies I can't mock.

To keep this lightweight feeling when working with node you need an approach for dependency injection that doesn't add too much complexity. Your express example above reminds me of a talk by Vojta Jina in which he makes an important point about the wiring part of dependency injection. (Watch minute 3:35 to 8:05) I can't explain it any better than Vojtja does in his talk but basically he says that we need a di framework that takes care of the wiring (what is injected into what). Otherwise the code we manually write to set up the wiring won't be maintainable. Also each unit test would need such wiring code. And that IMO is where manual dependency injection is not an option anymore.

When you use a di framework (or a di container as many people say) the basic idea is that each individual module states which dependencies it requires and through which id it can be required by other modules. Then the di framework can be invoked to initialize the module that serves as an entry point (e.g. app.js) and the framework will look up all dependencies and takes over the hard work of injecting the appropriate module instances.

There are many di frameworks for node.js to which I'd like to add my own: "Fire Up!" If you would use it your example would look like this:

foo.js

// Fire me up!

function Foo(fs) {
    this.fs = fs;
}

Foo.prototype.index = function () {
    var self = this;

    return function (req, res, next) {
        // self.fs...
    };
};

module.exports = {
    implements: 'foo',
    inject: ['require(fs)'],
    _constructor: Foo
};

bar.js

// Fire me up!

module.exports = {
    implements: 'bar',
    inject: ['require(fs)'],
    factory: function (fs) {
        return {
            index: function (req, res, next) {
                // fs...
            }
        };
    }
};

app.js

// Fire me up!

module.exports = {
    implements: 'app',
    inject: ['require(express)', 'foo', 'bar']
};

module.exports.factory = function (express, foo, bar) {
    var app = express();

    app.get('/foo', foo.index());
    app.get('/bar', bar.index);
};

index.js

var fireUpLib = require('fire-up');

var fireUp = fireUpLib.newInjector({
    basePath: __dirname,
    modules: ['./lib/**/*.js'] // foo.js, bar.js, app.js are on this path
});

fireUp('app'); // This is where the injection is kicked off.

When running node index.js you get the following output:

fireUp# INFO  Requested: app, implemented in: lib/app.js
fireUp# INFO  |-- Requested: require(express)
fireUp# INFO  |-- Requested: foo, implemented in: lib/foo.js
fireUp# INFO      |-- Requested: require(fs)
fireUp# INFO  |-- Requested: bar, implemented in: lib/bar.js
fireUp# INFO      |-- Requested: require(fs)

If this looks worth trying out you might be interested in the Getting Started section which shows an example based on express.

Hope that helps!

like image 167
analog-nico Avatar answered Sep 29 '22 00:09

analog-nico


You can check https://www.npmjs.com/package/plus.container

This is close to DIC in Symfony

like image 38
slava Avatar answered Sep 29 '22 02:09

slava