Published December 15, 2015

How to do Dependency Injection in node.js?

Dependency Injection is a pattern that helps you create loosely coupled codebases. You can swap collaborators and make your code testable. You can do dependency injection without additional libraries.

It’s one of the common questions asked among node.js developers. I’d like to share my preferences. Read below!

Introduction

Here’s two common questions I’m hearing very often when people start using node.js:

Q: How do I overwrite require for testing?

A: Use rewire/proxyquire/another require overwriting module.

Me: Please, don’t!

 

Q: How do I do DI in node?

A: Someone is already working on a Spring clone.

Me: Hopefully not.

 

The essence

Screen Shot 2015-12-06 at 12.30.33

 

I found this tweet the other day and I think it nails what we should focus on when thinking about DI in any language, not just Javascript.

So to follow along, here’s how to do dependency injection in Javascript:

  • using constructor functions: 
     new A(new B(), new C());

     

  • or even better*, using regular functions: 
    a(b(), c());

* without behind the scenes magic that happens with constructor functions

 

Example

So what does it look like in a sample node.js project?

Imagine a hypothetical CRUD application for a book inventory service. It has different HTTP routes for stocking the items up and checking the stock count. The actual interaction with a data store is implemented through a repository object with two flavours: mongo database backed and in-memory one.  

Screen Shot 2015-12-06 at 14.33.12

How can we compose the object graph for this application?

I like to build my graph of objects somewhere in the entry point of my application.

app.js

module.exports = function (config) {
   var stockRepository = (config && config.stockRepository) || mongoStockRepository();
   var routes = require('./routes')(stockRepository);

   var express = require('express');
   var app = express();
  
   app.get('/stock/:isbn', routes.getCount);
   app.post('/stock', routes.stockUp);

   return app;
};

function mongoStockRepository() {
   var url = process.env.MONGO_URI;
   var MongoClient = require('mongodb').MongoClient;
   var connection = MongoClient.connect(url);
   return require('./mongoStockRepository')(connection);
}

Then in my E2E tests I can swap mongo repository for the in-memory one:

var inMemoryStockRepository = require('../inMemoryStockRepository')();
var app = require('../app')({stockRepository: inMemoryStockRepository});

Individual modules can expose their injection points:

  • as simple function arguments:

routes.js

module.exports = function(stockRepository) {}

mongoStockRepository.js

module.exports = function (connection) {}
  • as object literal to simulate named arguments as we’ve seen in app.js with the config object

 

Using this technique you have only stateless requires (e.g. utility modules like lodash, ramda) spread across your codebase. Your code is testable at the individual module level but also at the application level in E2E tests.

 

Not just testability, but replaceability

I found that using Dependency Injection allows for easier evolution of your code. You can swap your dependencies over time and easily add new capabilities to the system, following Open Closed Principle. In other words, you can pass new arguments with the same (duck-typed) interface, but with a different implementation without having to modify the original code that exposes the arguments.

 

DI tool?

I also didn’t find a case for using more advanced DI tool. I usually know at code writing time what dependencies I need and building the graph of objects myself is easier to reason about than thinking about some magic framework sauce.

Published December 15, 2015