2

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.

Ed S.
  • 122,712
  • 22
  • 185
  • 265

1 Answers1

4

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.

rob
  • 9,933
  • 7
  • 42
  • 73
  • Sounds good to me, thank you sir. It's hard finding real world type usage in tutorials, off to find some open source code to review... – Ed S. Nov 15 '11 at 23:02
  • One problem I noticed last night with my approach; it is difficult to distinguish between launching a script and requests for static resources. I'll go with one of the routers in github at this point since this was more of a learning experience anyway. I would likely need to filter by location on GET's before routing the request. – Ed S. Nov 16 '11 at 19:11
  • In several things I've worked on, I include the node_static module. Using it, you can first check if the request can be handled as a static resource, and if not, try to handle it as a script. Or the other way round. – rob Nov 16 '11 at 19:53
  • Ahhh, thanks for that. I'm still making my way through the gigantic list of modules and taking note of what I may find useful in the future. – Ed S. Nov 16 '11 at 19:54