Routing requests and structuring response handlers in Node

Problem

So I am a systems programmer currently teaching myself web application programming. As is always the case when learning something new, I don't yet have a firm grasp on idiomatic implementations, or simply put, how to do something the "right" way.

After taking some time building a few games and trivial UI's using nothing but HTML and javascript, I am now venturing out into a non-trivial dynamic application. I am using Node as my server and have a question concerning how to route response handlers.

I am following a (seemingly) nice guide found here. This is the only guide I have found so far that takes you through how to build an actual application (as opposed to something like response.write("Hello world"); response.end();).

The author proposes adding response handlers like so:

var server = require("./server");
var router = require("./router");
var requestHandlers = require("./requestHandlers");

var handle = {}
handle["/"] = requestHandlers.start;
handle["/start"] = requestHandlers.start;
handle["/upload"] = requestHandlers.upload;

server.start(router.route, handle);

The code should be self-explanatory, but essentially he is using an object as an associative container to map the resource requested in a query string to a handler. That's all well and good, but I would like to avoid adding a line to this file every time I add a new handler.

My idea was this; create a module for each handler and use some common interface to handle the response. Something like:

function handleReq(...) {
    ...
}

exports.handleRequest = handleReq;

I could then just require the module dynamically, i.e.,

// in my router module
function route(pathName, args) {
    // where 'pathName' is something obtained
    // in a manner like so in the request handler:
    // url.parse(request.url).pathname;  

    var handler = require(pathName);
    handler.handleRequest(args);
}

Is there some flaw I am not seeing in this approach? It seems as though it would cut down on redundant code, but being a beginner in this field/technology I am suspicious. Perhaps the author just wanted to keep it simple, or as I guess may be the case, I am missing something.

Cheers and thanks in advance. Don't feel free to throw other seemingly unrelated advice at me as well should you see a reason to do so.

Problem courtesy of: Ed S.

Solution

There are lots of ways of doing such things, I think the guide was trying to be simple.

I tend to do stuff like this: Create modules that have handlers in them, and to add a new handler just add it to the module in the right place, and it will automatically work...no need to modify any other code. The server code just has to try calling moduleName.handleRequest(scriptName, req, resp); and if it returns true, it was successful. (it can try it on all the modules that have handlers, if none return true, it can show a 404)

scriptName is assumed to have had the path trimmed off it (so "/start" would just be "start", etc), if you really need to use the path in determining which handler to dispatch it to, I'm sure you could build that in in an elegant way, but I didn't bother.

Within the module itself, you can have something like this:

var handlers = {
 start : function (req, resp) {
  // ...
  },

 upload : function (req, resp) {
  // ...
  } 
};

export.handleRequest(name, req, resp) {
  if (handlers[name] !== undefined) {
    handlers[name](req,resp);
    return true;
  }
  // do special cases (if there are any)
  if (name === '') {
    handlers.start(req,resp);
    return true;
  }
  return false; // not found
}

This is really just one step up in terms of complexity/sophistication from the example you cite. You can keep going till you have a full-fledged framework.

Solution courtesy of: rob

Discussion

There is currently no discussion for this recipe.

This recipe can be found in it's original form on Stack Over Flow.