Elegant request routing in Nitro
by gmosx, at 05 Jul 2010During the initialization of a Web application, Nitro performs a scan of the src/root directory and constructs a sitemap. The Path middleware leverages this structure to intelligently split incoming request paths to the corresponding scriptName and pathInfo components.
The scriptName component is the path of the JSGI application that will handle the request. If the Render middleware is used, the template path is also derived from scriptName. The pathInfo component stores the extra postfix of the request. Let's use an example to demonstrate the concept:
Given the directory structure (sitemap):
/src/root/articles.js
/src/root/articles/view.js
Nitro automagically splits the request path:
/articles/12339
into:
scriptName: /articles
pathInfo: /12339
since /src/root/articles/12339.js does not exist.
We can use the pathInfo component to implement nice, RESTful URLs. In the context of the above example, we can implement routing through a filter function in articles.js:
/articles.js:
var upstream = require("./articles/view");
var Route = function (app) {
return function (request) {
if (request.pathInfo.length > 0) {
request.scriptName = "/articles/view";
request.params.key = request.pathInfo.split("/")[1];
return upstream.GET(request);
} else {
return app(request);
}
}
}
exports.GET = Route(function (request) {
..
});
/articles/view.js:
var Article = require("content/article").Article;
exports.GET = function (request) {
var article = Article.get(request.params.key);
}
The filter code in articles.js dispatches to articles/view.js when a pathInfo component is detected.
I find this technique simple, elegant and effective. It's fast too as you don't need to scan through a URL map. What do you think?
Tip: You can use request.dispatch(request) instead of upstream.GET(request) to make the Route filter more reusable (request.dispatch() can handle any HTTP method).


