Modules are the basic building blocks of Node.js applications. With all our changes, our file is becoming a bit clumsy; moreover, we are putting our infrastructure (server and router) with the application logic (the handlers) in the same place. As mentioned earlier, Node.js builds on the CommonJS module system. In Node.js, a module and a file have a one-to-one relation. Let us move the server and router to their own modules. Save the following in a file called server.js
:
var http = require("http"); var url = require("url"); function onRequest(request, response) { var pathname = url.parse(request.url).pathname; console.log("Request for " + request.method + pathname +" received."); if(typeof(routes[request.method + pathname])==='function'){ routes[request.method + pathname](request, response); } else{ response.writeHead(404, {"Content-Type": "text/plain"}); response.end("404 Not Found"); } } var routes = {}; exports.forRoute = function(method, path, handler){ routes[method + path] = handler; }; exports.start = function(){ http.createServer(onRequest).listen(9999); console.log("Server has started."); };
Most of the logical aspects of the code remain the same, but we have made some very subtle structural changes. The first one is that we have taken the routes out of the route
object. Any variables declared in the file are available within the module and are not accessible from outside the module.
if(typeof(routes[request.method + pathname])==='function'){ routes[request.method + pathname](request, response); }
As the route
object is gone, we can now directly access the routes within the module and not through the route
object.
The other and more obvious change is exports
. Since nothing from within the module is available outside the module, we have to add the methods/objects that we want to expose to the implicit exports
object. Ideally, you should expose only those methods relevant to the end user of your module.
exports.forRoute = function(method, path, handler){ routes[method + path] = handler; }; exports.start = function(){ http.createServer(onRequest).listen(9999); console.log("Server has started."); }
We are exposing two methods from our module: the forRoute
method (originally, the on
method in the route
object), and the start
method that wraps the code to start the HTTP server. We also move the application logic to its own module called app.js
, which is shown in the following code snippet:
var server = require("./server.js"); server.forRoute("GET", "/start", function(request, response){ response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello"); response.end(); }); server.forRoute("GET", "/finish", function(request, response){ response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Goodbye"); response.end(); }); server.forRoute("POST", "/echo", function(request, response){ var incoming = ""; request.on('data', function(chunk) { incoming += chunk.toString(); }); request.on('end', function(){ response.writeHead(200, {"Content-Type": "text/plain"}); response.write(incoming); response.end(); }); }); server.forRoute("GET", "/echo", function(request, response){ var body = '<html>' + '<head><title>Node.js Echo</title></head>' + '<body>' + '<form method="POST">' + '<input type="text" name="msg"/>' + '<input type="submit" value="echo"/>' + '</form>' + '</body></html>'; response.writeHead(200, {"Content-Type": "text/html"}); response.write(body); response.end(); }); server.start();
Again, the logical aspects remain unchanged; the changes are only in the structure.
var server = require("./server.js");
The previous line, which is also the first line in the previous code snippet, shows us how our server module is loaded. This is similar to loading core modules like HTTP or URL, but here we are loading the module and passing its filename. The object created by this require
method, the server
object, will have two methods that will be exposed: forRoute
and start
.
Next, we replace all the calls to route.on
with the server.forRoute
method. . And finally, we call the server.start
method to start the HTTP server.
server.start();