3

I'm using Inversify.JS in a project with Express. I would like to create a connection to a Neo4J Database, and this process has two objets:

  1. The driver object - Could be shared across the application and created one time only
  2. The session object - Each HTTP request should create a session against the driver, whose lifecyle is the same as the http request lifecycle (as long as the request ends, the connection is destroyed)

Without Insersify.JS, this problem is solved using a simple algorithm:

exports.getSession = function (context) { // 'context' is the http request 
  if(context.neo4jSession) {
    return context.neo4jSession;
  }
  else {
    context.neo4jSession = driver.session();
    return context.neo4jSession;
  }
};

(example: https://github.com/neo4j-examples/neo4j-movies-template/blob/master/api/neo4j/dbUtils.js#L13-L21)

To create a static dependency for the driver, I can inject a constant:

container.bind<DbDriver>("DbDriver").toConstantValue(new Neo4JDbDriver());

How can I create a dependency instantiated only once per request and retrieve them from the container?

I suspect I must invoke the container on a middleware like this:

this._express.use((request, response, next) => {
    // get the container and create an instance of the Neo4JSession for the request lifecycle
    next();
});

Thanks in advance.

Fer2D2
  • 51
  • 7
  • In case anyone needs to resolve instances PER HTTP REQUEST with InversifyJS, not just with Express, but any framework/environment, here's a solution: https://stackoverflow.com/a/71180025/484108 – Phillippe Santana Feb 18 '22 at 21:28

1 Answers1

1

I see two solutions to your problem.

  1. use inRequestScope() for DbDriver dependency. (available since 4.5.0 version). It will work if you use single composition root for one http request. In other words you call container.get() only once per http request.
  2. create child container, attach it to response.locals._container and register DbDriver as singleton.

    let appContainer = new Container()
    appContainer.bind(SomeDependencySymbol).to(SomeDependencyImpl);
    
    function injectContainerMiddleware(request, response, next) {
         let requestContainer = appContainer.createChildContainer();   
         requestContainer.bind<DbDriver>("DbDriver").toConstantValue(new Neo4JDbDriver());
         response.locals._container = requestContainer;
         next();
    }
    
    express.use(injectContainerMiddleware); //insert injectContainerMiddleware before any other request handler functions
    

In this example you can retrieve DbDriver from response.locals._container in any request handler/middleware function registered after injectContainerMiddleware and you will get the same instance of DbDriver

This will work, but I'm not sure how performant it is. Additionally I guess that you may need to somehow dispose requestContainer (unbind all dependencies and remove reference to parent container) after http request is done.

robak86
  • 337
  • 2
  • 7