Node.js itself is pretty bare bones. It's not a framework like Rails, but rather plain request-response handling. It's sort of like Python's Twisted framework, from what I gather.
There are more full-featured frameworks for node.js if you look around on github, but I'm bored and feel like committing the sin of writing yet more framework code.
This morning I started with a request router for Node.JS that leverages URI templates*. You specify the application as a series of request templates, paired with the functions that handle them.
For instance if you take the typical blogging application example, you might have a path like /posts/1234 - and the URI template would look like /posts/{postId}.
The magic is in turning {param}s in the URI template into parameters in the handler call.
Here's an example app that routes blog-like requests:
var handlers = { '/posts/{postId}' : { GET : function(postId) { this.response.sendHeader(200, {"Content-Type": "text/plain"}); this.response.sendBody("GET Post ID: " + postId); this.response.finish(); }, POST : function(postId) { this.response.sendHeader(200, {"Content-Type": "text/plain"}); this.response.sendBody("POST Post ID: " + postId); this.response.finish(); } }, '/comments/{postId}/{commentId}' : { GET : function(postId, commentId) { this.response.sendHeader(200, {"Content-Type": "text/plain"}); this.response.sendBody("GET Post ID: " + postId + " Comment ID: " + commentId); this.response.finish(); } } };
As you can see the individual handler functions are further distinguished by HTTP method.
I'm not sure how to pass POST bodies to the handlers. They could just be attached to the handler's this I suppose.
Here's the full source:
var sys = require("sys"), http = require("http"); var handlers = { '/posts/{postId}' : { GET : function(postId) { this.response.sendHeader(200, {"Content-Type": "text/plain"}); this.response.sendBody("GET Post ID: " + postId); this.response.finish(); }, POST : function(postId) { this.response.sendHeader(200, {"Content-Type": "text/plain"}); this.response.sendBody("POST Post ID: " + postId); this.response.finish(); } }, '/comments/{postId}/{commentId}' : { GET : function(postId, commentId) { this.response.sendHeader(200, {"Content-Type": "text/plain"}); this.response.sendBody("GET Post ID: " + postId + " Comment ID: " + commentId); this.response.finish(); } } }; var Route = function(uriTemplate) { this.uriTemplate = uriTemplate; var nameMatcher = new RegExp('{([^}]+)}', 'g'); this.paramNames = this.uriTemplate.match(nameMatcher); // the regex keeps the {} on the param names for some reason. TODO: fix this. for (var i = 0; i < this.paramNames.length; i++) { this.paramNames[i] = this.paramNames[i].replace('{', '').replace('}', ''); } this.matcherRegex = this.uriTemplate.replace('?', "\\?").replace(/{([^}]+)}/g, '([^/?&]+)'); this.matcher = new RegExp(this.matcherRegex); }; Route.prototype.parse = function(path) { if (this.matcher.test(path)) { var result = {}; var paramValues = this.matcher.exec(path); // assert: paramValues.length == paramNames.length for (var i = 1; i < paramValues.length; i++) { result[this.paramNames[i-1]] = paramValues[i]; } return result; } return null; //throw exception? }; http.createServer(function (request, response) { var handled = false; for (pathTemplate in handlers) { var route = new Route(pathTemplate); var params = route.parse(request.uri.full); if (params) { // Convert the results to an array so we can pass them in via apply(). var values = []; for (name in params) { values[values.length] = params[name]; } var handler = handlers[pathTemplate][request.method]; // So you can call this.request and this.response in the handlers. handler.apply({'request' : request, 'response' : response}, values); handled = true; } } if (!handled) { response.sendHeader(404, {"Content-Type": "text/plain"}); var output = "Couldn't route: " + request.uri.full + "\n"; for (name in request) { output += name + ": " + request[name] + "\n"; } response.sendBody(output); response.finish(); } }).listen(8000); sys.puts("Server running at http://127.0.0.1:8000/");The route lookup in the http.createServer could be a lot more efficient, like memoizing Route objects for instance.
Anyways, NodeJS looks pretty exciting. Combined with CouchDB you could have a full JavaScript application stack: from storage to app server to client.
*Yes, I realize this is not a full implementation of the URI template spec. It's just a proof of concept.
Hm. It just occurred to me that the URI template parameter-to-function-parameter mapping is positional, so that the names in the template must be in the same order as the names in the handler function. So you could't change /comments/ handler to take (commentId, postId) and have it still work. This code would produce the reverse of what would would expect for those two parameter values.
ReplyDeleteInstead of calling apply() with the parameter array, it could just pass in the Route.parse() results as a single parameter to the handler.
Hmm. But it's still ends up as a regex. What's the point (besides somehow clearer syntax)? Regex-only URI (like the ones implemented in `nerve`) will be much more flexible.
ReplyDeleteOn the other hand, for simple tasks as this, I think clear syntax will outweight other concerns.
Clearer syntax is the point. How often do you need the full power of RegExp for path parsing? Rarely. And you end up with typos, unintentionally greedy patterns that match other handlers' request paths. Really RegExp is overkill.
ReplyDeletePLUS- this method uses the variable {names} from the URI template as the actual variable names returned in a match. So you don't have to iterate through the RegExp match groups manually looking for a parameter from the URI.
I'd check if the request.method exists in the handler and return a 405 otherwise.
ReplyDeleteugg boots sale
ReplyDeleteair jordan 13 retro
prada sneakers
polo ralph lauren factory store
cheap canada goose jackets
jordan shoes
abercrombie
ray ban sunglasses
nike outlet store online shopping
coach handbags outlet
kobe bryant shoes
ghd
christian louboutin sale
abercrombie & fitch
michael kors handbags clearance outlet
canada goose jackets
oakley sunglasses
cheap jordans
hermes belt
michael kors outlet 90% off
jordan infrared 6
michael kors store
gucci outlet
20151028yxj-2
Yours information was of great help.
ReplyDeletewww.opcionesbinarias.site
coach outlet
ReplyDeletechristian louboutin
coach factory outlet
kobe 9
replica rolex
nba jerseys
ray ban sunglasses
coach outlet online
saics running shoes
true religion jeans
air jordan uk
ReplyDeletelions jerseys
cincinnati bengals jerseys
cheap jordans
nhl jerseys
oakley sunglasses
under armour shoes
new york knicks
oakley sunglasses wholesale
chicago bears jerseys
victoria's secret outlet
ReplyDeleteherve leger dresses
uggs outlet
lebron soldier 11
saint laurent sunglasses
supra shoes
columbia sportswear
tom ford sunglasses
tommy hilfiger
ray ban outlet
20189.15chenjinbei
hermes
ReplyDeletejordan pas cher
mizuno
karen millen
converse shoes
brazil world cup jersey
hermes birkin
mac cosmetics
gucci outlet
ralph lauren outlet
2018.10.23xukaimin
ReplyDeletegood Company Registration in Bangladesh
outsourcingall is a Porn Training site. outsourcingall.com is the largest Amateur porn training institute with the hottest selection Online and offline
Free sex videos
Merit Casino - Find Official Portal
ReplyDeleteDiscover the Best Merit Casino Portal for kadangpintar all things casino deccasino related on the internet! Discover your favorite 카지노사이트 games and casinos here.Contact Us · Support