3

Knowing that Express.js pretty much leaves it to developer on deciding app structure, and after reading quite a few suggestions on SO (see link1 and link2 for example) as well as checking the example in official repo, I am still not sure if what I am doing is the best way forward.

Say I am using Redis extensively in my app, and that I have multiple "models" that require redis client to run query, would it be better to init redis client in the main app.js, like this:

var db = redis.createClient();
var models = require('./models')(db);
var routes = require('./controllers')(models);

or would it be better to just init redis in each model, then let each controller require models of interests?

The latter approach is what I am using, which looks less DRY. But is passing models instance around the best way? Note that I am loading multiple models/controllers here - I am not sure how to modify my setup to pass the redis client correctly to each models.

//currently in models/index.js

exports.home = require('./home.js');
exports.users = require('./user.js');

TL;DR, my questions are:

  1. where best to init redis client in a MVC pattern app?
  2. how to pass this redis client instance to multiple models with require('./models')(db)

Update:

I tried a different approach for index.js, use module.exports to return an object of models/controllers instead:

module.exports = function(models){

  var routes = {};

  routes.online = require('./home.js')(models);
  routes.users = require('./user.js')(models);

  return routes;

};

Seems like a better idea now?

Community
  • 1
  • 1
bitinn
  • 9,188
  • 10
  • 38
  • 64

1 Answers1

3

Perhaps it's useful if I share how I recently implemented a project using Patio, a SQL ORM. A bit more background: the MVC-framework I was using was Locomotive, but that's absolutely not a requirement (Locomotive doesn't have an ORM and it leaves implementing how you handle models and databases to the developer, similar to Express).

Locomotive has a construct called 'initializers', which are just JS files which are loaded during app startup; what they do is up to the developer. In my project, one initializer configured the database.

The initializer established the actual database connection, also took care of loading all JS files in the model directory. In pseudocode:

registry = require('model_registry'); // see below
db       = createDatabaseConnection();
files    = fs.readDirSync(MODEL_DIRECTORY);
for each file in files:
  if filename doesn't end with '.js':
    continue
  mod = require(path.join(MODEL_DIRECTORY, filename));
  var model = mod(db);
  registry.registerModel(model);

Models look like this:

// models/mymodel.js
module.exports = function(db ) {
  var model = function(...) { /* model class */ };
  model.modelName = 'MyModel'; // used by registry, see below
  return model;
};

The model registry is a very simple module to hold all models:

module.exports = {
  registerModel : function(model) {
    if (! model.hasOwnProperty('modelName'))
      throw Error('[model registry] models require a modelName property');
    this[model.modelName] = model;
  }
};

Because the model registry stores the model classes in this (which is module.exports), they can then be imported from other files where you need to access the model:

// mycontroller.js
var MyModel = require('model_registry').MyModel;
var instance = new MyModel(...);

Disclaimer: this worked for me, YMMV. Also, the code samples above don't take into account any asynchronous requirements or error handling, so the actual implementation in my case was a bit more elaborate.

robertklep
  • 198,204
  • 35
  • 394
  • 381
  • interesting, so you basically keep a collection of models in ```module.exports```, I wonder how it compares to keeping module in GLOBAL - http://stackoverflow.com/questions/5447771/node-js-global-variables – bitinn Mar 29 '13 at 14:27
  • It's a matter of taste, I think. I myself prefer having to perform some explicit action to retrieve a variable instead of it being 'just there' :) – robertklep Mar 29 '13 at 14:41