Work with Routing in Node.js


Reading time: 25 minutes

In this article, we will take a look at how routing works in Node.js and set up different routes with combinations of pathname and query to test our idea.

You will get an idea of implementing three third types of routes:

  • URLs with no queries and only pathname (my-app/pathname)
  • URLs with queries and pathname both (my-app/pathname?query1=q2)
  • URLs that do not match any pathname

⭐ Introduction


somewebsite.com_someroute

Routing basically means implementing different actions for different URLs. For instance,
www.facebook.com/messages takes you to the message route, while www.facebook.com/notifications takes you to the notifications route, similarly www.facebook.com/friends takes you to some altogether different route.

The goal of this tutorial is to implement the entire routing procedure from scratch.
Now routing can actually become very very complicated in a big, real world application,and so in that case we use a tool like Express.

But for now, since we're just starting to learn Node, let's learn how to do everything from scratch without any of these dependencies!

So, follow the steps to implement Routing in your application -

⭐ Step 1 : Creating a Web Server


To learn how to create a web server, you may refer the following , tutorial . Or you can simply download the starter files for the project
here.

⭐ Step 2 : Analyze the URL


To analyze the URL, we use a built-in Node module k/a url.
So include the package using const url = require('url'). Now, let's see what url module actually does - write down console.log(req.url) inside createServer() function.

const server = http.createServer((req, res) => {
    console.log(req.url)
  res.writeHead(200, { "Content-Type": "text/html" });
  res.write(" Hello from the Server! ");
  res.end();
});

Now, open the terminal, traverse to the working directory, and run node index.js .
The server is running on 127.0.0.1:8000. Open your browser and go to 127.0.0.1:8000.
You may see the following results in your terminal -

node-a

Here, we have the URL, and actually 2 URLs. One is the /, which refers to our homepage, and the other is favicon.ico. And this is because when we are using the browser, the browser automatically requests for the website's favicon.

Now, type in 127.0.0.1:8000/overview in your browser, and see the results. This time, there are again two requests - for /overview and favicon.ico.

url.parse() - We can parse the URL using url.parse(). It returns a URL object with each part of the address as properties.
Now, let's analyze the complete url object using url.parse().

console.log(url.parse(req.url, true));

Save the file, use Cmd+C or Ctrl+C to restart the server, reload the webpage, and have a look at your terminal.
This is how the object looks -

node-a-1

The query field refers to the query parameters in the url, similarly pathname refers to the pathname specified in the url. For instance, reload the browser with the address http://127.0.0.1:8000/overview?id=1, and now let's have a look at the terminal -

node-b

The query parameter, i.e id is present in the query field, while the pathname i.e /overview is present in the pathname field.

⭐ Step 3: Implement the routing :


Okay before implementing routing in our code, let's understand the way we can hadle routing for different kind of URLs.

📝 URLs with no queries and only pathname


URLs with only pathname look similar to:

https://my-app/pathname/

To handle such queries we use the field pathname from the object returned by url.parse() method.

For instance,

    1. const { pathname } = url.parse(req.url, true);
    2. if (pathname === "/product") {
    3. res.writeHead(200, {
    4. "Content-type": "text/html"
      });
    5. res.end("This is the product");
    }

In line 1, We have fetched the value of the field pathname in a variable k/a pathname .
In line 2, using if-else we have compared the pathname for a specific route ('product' in our case).
In line 3, we have mentioned the status code of our response i.e 200. 200 means OK.
In line 4, we have mentioned the content type of our response.
In line 5, we have sent a plain text response to the browser.

📝 URLs with queries and pathname both


URLs with pathname and query look similar to:

https://my-app/pathname?query1=q2

To handle such queries we use the field pathname and query from the object returned by url.parse() method.

For instance,

 1.    const { pathname, query } = url.parse(req.url, true);
 2.    else if (pathname === "/api/" && query.name) {
 3.    res.writeHead(200, {
 4.    "Content-type": "text/html"});
 5.    const data = fs.readFileSync(`./data-${query.name}`, "utf-8");
 6.    res.end(data);
      }

In line 1, We have fetched the value of the field pathname and query in a variable k/a pathname and query .
In line 2, using if-else we have compared the pathname for a specific route ('product' in our case) and checked for if the query name is present.
In line 3, we have mentioned the status code of our response i.e 200. 200 means OK.
In line 4, we have mentioned the content type of our response.

Note : We can use the query in the URL for fetching a particular document from database, or for performing a particular operation. Here, we'll be using the query to fetch contents from a file,( where file name depends on the query) and then render it to the browser.

In line 5, using the name query, we fetch content from a file using the fs (file-system) module .

Here, the file name is data-OpenGenus, with the following content -

OpenGenus Foundation is an open-source non-profit organization with the aim to enable people to work offline for a longer stretch, reduce the time spent on searching by exploiting the fact that almost 90% of the searches are same for every generation and to make programming more accessible. OpenGenus is all about positivity and innovation ! !

Using this code, and url http://127.0.0.1:8000/api/?name=OpenGenus we may get a response like this -

node-h

📝 URLs that do not match any pathname


Often during surfing the internet, we have encountered 404 pages. 404 stands for Not Found. For URLs that do not match any pathname in our program, we can add a simple else block to tackle all such URLs.

For instance

else {
res.writeHead(404, {
"Content-type": "text/html",
"my-own-header": "hello-world"
});
res.end("<h1>Page not found!</h1>");
}

Here, we have simply used an else block to prevent our program from crashing for URLs that we have not mentioned in our code.

And now, we are all ready to implement routing in our code.
Include the following code in your index.js, and then let's understand the step by step process -

const server = http.createServer((req, res) => {
    const { pathname } = url.parse(req.url, true);

    // Overview page
    if (pathname === "/" || pathname === "/overview") {
      res.writeHead(200, 
      
        "Content-type": "text/html"
      });

      res.end("This is the OVERVIEW !");

      // Product page
    } else if (pathname === "/product") {
      res.writeHead(200, {
        "Content-type": "text/html"
      });
      res.end("This is the product");

      // API
    } else if (pathname === "/api") {
      res.writeHead(200, {
        "Content-type": "application/json"
      });
      res.end("This is the API");

      // Not found
    } else {
      res.writeHead(404, {
        "Content-type": "text/html",
        "my-own-header": "hello-world"
      });
      res.end("<h1>Page not found!</h1>");
    }

  console.log(url.parse(req.url, true));
  res.end("Hello I am the OVERVIEW !");
});

So what's actually happening ?

  1. A server is created using createServer() method.
  2. Once we load the page in our browser, the method gets fired off.
  3. Using destructuring, we have extracted the pathname from the object returned by the url.parse() method.
  4. We have defined routes(Overview, Product, Api, Page not found) using simple if else method using the pathname variable.
  5. For each route, we have specified the response status, its content type and the text message.

⭐ Step 4: Test the routing :


Now, time to test our routing, so save the file, reload the server and head over to your browser.

Go to 127.0.0.1:8000/overview in your browser, and we get the following response -
node-c

Now test for 127.0.0.1:8000/product, and you may get the following response -
node-d

Let's test for the api route now, 127.0.0.1:8000/api, and we get the following response -
node-e

And finally for the route that's not defined in our code, 127.0.0.1:8000/random-page, we get the following response -
node-f

And We're all done !! 🎉

⭐ References/Further Reading :


  1. https://nodejs.org/api/url.html
  2. https://www.npmjs.com/package/url