Recently I have introducted Node.js and Express framework into my project which is very modular.
One of principles is that each functionality is encapsulated into a Controller known from web applications
frameworks like as Spring, Zend, Symfony, etc. Controller is nothing other than a function/method that will be executed, when the client’s HTTP request incomes.
It is very convenient to autoload all controllers from specified directory, which intends to register into URL routing registry. Assume, that all controllers exists in /src/Controller/
directory.
We could use the fs module from the Node.js standard library and call fs.readdir(path)
or fs.readdirSync(path)
, but methods doesn’t works recursive. There is a lot of methods to walk trought the directory tree, but I have used an existing wrench module written by Ryan McGrath.
The usage
of my ModuleLoader
moduleLoader.loadModulesFromDirectory(path, onLoadCallback)
where onLoadCallback is function(module, moduleName, filePath)
.
Code
exports.loadModulesFromDirectory = function(dir, onLoadCallback) {
require('wrench').readdirRecursive(dir, function(error, files) {
if(null === files)
return;
for(var i = 0, j = files.length; i < j; ++i) {
var file = files[i];
if(!file.match(/\.js$/))
continue;
var moduleName = file.substr(0, file.length - 3);
var filePath = dir + "/" + file;
var module = require(filePath);
onLoadCallback(module, moduleName, filePath);
}
});
}
Simple. Let’s use
this to load our Node.js and Express web application controllers:
1. Create the package.json
file:
{ "name": "hello-world", "description": "testapp", "dependencies": { "express": "3.2.6", "wrench": "1.5.1" } }
2. Create the server.js
file which will contain our web server:
var express = require('express'); var app = express(); var routes = require('./config/routes'); var port = process.env.port || 3000; console.log('Starting server at port ' + port); routes.setup(app); app.listen(port);
3. Define our ./config/routes.js
file:
function setup(app) {
var moduleLoader = require('ModuleLoader');
var path = __dirname + "/../src/Controller";
moduleLoader.loadModulesFromDirectory(path, function(module, moduleName, filePath) {
var loadingState = "";
if(typeof module.registerAutoload === 'function') {
module.registerAutoload(app);
loadingState = "OK";
}
else {
loadingState = "FAILED";
}
console.log("Loading Controller >> " + moduleName + " >> from file " + filePath + ": " + loadingState + ".");
});
}
exports.setup = setup;
4. And the last one… create our test controller in ./src/Controller/Test.js
:
actionHello = function(req, res) {
res.end('Hello! Server date: ' + new Date());
}
exports.registerAutoload = function(app) {
app.get('/hello', actionHello);
}
If controller’s intention is not to autoload, just don’t implement exports.registerAutoload
method. It works like the autoloading controllers from specified namespace in Spring Framework to look up for classes with @Controller
annotation.
5. Now run our app!
To install all dependencies, use npm (Node Packaged Modules):
npm install
After installing all dependencies, the node_modules wil be created. Now, ust run our app:
node server.js
Now, lunch: http://localhost:3000/hello
Pretty, isn’t it?
Hope it helped.