Before talking about anything related to improved routing, I have a question for you. If you have ever used any web development framework in the past, in any programming language, do you feel that we are creating a mini web framework with our own hands? If yes, then I think you have carefully gone over and wrote each and every code line of code shown in this series of articles by your own hands. But our primary intention is not to develop another web application framework. Our intention is to develop a sophisticated web application without using any third party web development framework for Node.js. When we face a problem, we solve it on our own without falling back on a framework. In this way you will not only learn how to develop a web application with Node.js, but also you will learn how to create a framework or library of your own when you see recurring patterns in your domain.

In the previous article we implemented routing system in our application and now it’s easier than ever before to add another URL pattern and a handler/view for it. The code of all the articles can be found on the Github repository Learn Node.js With Sabuj. Code for each article is separated into branches on the repository. Code for the current article can be found on the branch named "007_implementing_routing_2."

In the previous article we implemented a routing system in our application in a way that everything worked as before. But did you notice that if you enter an unknown URL to the routes, the browser will never receive a response? It will look as if our application is in a hanging state. It does not even return a 404 or 500 code. So, we need to fix this very important problem.

Before proceeding in that direction, I want to refactor the handleSimpleForm() function from our custom utils module. It accepts parameters in the order of url, request, response, but in the handlers we put them in the order request, response, url. This may lead to serious bugs in future. So, let's change the signatures and its uses.

utils.js

exports.handleSimpleForm = function handleSimpleForm(request, response, url_comps){ ... }

We need to change its use in process_forms.js:

exports.process_form = function(request, response, url){ utils.handleSimpleForm(request, response, url); }

Let's get back to fixing the primary issues we are currently facing. So, we need a view when there is no handler for an URL. To keep things dynamic let's create a variable in the routes module named view_404 that will hold a handler for responding to the user agent when a non existent URL is requested.

routes.js

var home = require("./views/home").home; var form = require("./views/form").form; var process_form = require("./views/process_form").process_form; var view_404 = require("./views/view_404").view_404; var routes = [ { pattern: '', handler: home }, { pattern: 'form', handler: form }, { pattern: 'submit-form', handler: process_form } ] exports.routes = routes; exports.view_404 = view_404;

By looking at the code it is apparent that we want to create file named view_404 inside the views directory and we want to export a handler function called view_404 from inside of it. Let's get to work.

view_404.js

exports.view_404 = function(request, response, url){ }

We want to send a status code of 404 and a status message of Requested resource not found.

view_404.js

exports.view_404 = function(request, response, url){ response.writeHead(404, "Requested resource not found"); }

We also want to provide the content type of text/html and in the response we want to send HTML informing what URL the user requested.

exports.view_404 = function(request, response, url){ response.writeHead(404, "Requested resource not found", { 'Content-Type': 'text/html' } ); response.write( "You requested the URL: <b>" + url.path + "</b> that was not found." ); response.end(); }

The last thing that we need to do now is to call view_404 when no pattern matches. We need to do this inside responder.js. Look at the code below.

var url = require('url'); var routes = require("../routes").routes; var view_404 = require('../routes').view_404; exports.serveRequests = function(request, response){ const url_comps = url.parse(request.url, true); console.log(request.method + " " + request.url); var path = url_comps.pathname; if (path.charAt(0) === '/'){ path = path.slice(1); } var found = false; for (var i = 0; i < routes.length; i++) { var router = routes[i]; var pattern = router.pattern; var handler = router.handler; if (pattern.charAt(0) === '/'){ pattern = pattern.slice(1); } if (path === pattern){ handler(request, response, url_comps); found = true; break; } } if (!found){ view_404(request, response, url_comps); } };

We introduced a new variable named found that will keep track of whether the router was found for the path or not. If it is not found then the view_404 handler will be called with proper arguments.

Fire up the terminal, start the application by running the main.js with node, go to the browser and enter the url: http://localhost:5000/invalid-url?p=q. If you haven't made any other mistakes then your application will work perfectly.

So, we have successfully implemented a dynamic routing system in our application. Now we won’t need to keep track of everything to add a new route, we don’t need to worry about what code to edit and where to do it. We can do that by editing our routes array, importing handlers functions, and keeping those handlers functions inside the views directory. Keep practicing with Node.js and check back soon for the next post.

About the Author

My name is Md. Sabuj Sarker. I am a Software Engineer, Trainer and Writer. I have over 10 years of experience in software development, web design and development, training, writing and some other cool stuff including few years of experience in mobile application development. I am also an open source contributor. Visit my github repository with username SabujXi.