Routing in Node.js (without framework)

Frameworks such as ExpressJS makes routing quite easy. But initially it is important to understand how routing works in Node. It is advised not to jump to ExpressJS straightaway.

Handling Incoming HTTP Requests and Sending HTTP Responses

When coming from a traditional server-side background (such as PHP), handling incoming urls in Node.js may initially look more of a pain.

In languages such as PHP or Java, a specific script is executed when a certain url is entered in the browser. PHP and Java are programming languages and not servers. The running servers (Apache, Tomcat etc) make the routing decisions, and route an incoming url to a specific PHP script or a Java file.

But Node.js is different :

  1. You are responsible for starting a server
  2. You are responsible to read incoming urls, make routing decisions
  3. You then perform actions based on the incoming url (like normally done in PHP or Java)
const http = require('http');

// create server
const server = http.createServer();

// this callback will be executed for EVERY incoming request
server.on('request', (request, response) => {
   // read incoming HTTP request
   // make routing decisions based on the request url 
});

// start server on port 8080
server.listen(8080);

Usually a shorthand is used to create the server and adding the "request" listener.

const server = http.createServer((request, response) => {
    // read incoming HTTP request
}); 

Structure of a URL

A url is comprised of a number of parts, commonly used ones are :

  • protocol - http or https
  • hostname - server name
  • pathname - path of the url
  • search - query string in the url

For example, the below url can be broken up into constituent parts :

http://usefulangle.com/post/87/javascript-preview-pdf?id=123&type=article
  • protocol - http
  • hostname - usefulangle.com
  • pathname - /post/87/javascript-preview-pdf-during-upload
  • search - ?id=123&type=article

Getting the HTTP Method

In Node, the HTTP method (GET, POST, DELETE etc) can be found with the method property of the request object.

const server = http.createServer((request, response) => {
    const method = request.method;
}); 

Reading the Request Url with the URL Object

In Node, the incoming url can be found with the url property of the request object.

const server = http.createServer((request, response) => {
    const current_url = request.url;
}); 

Please note that this request url is the full url, except the server, protocol or port — this means that it includes the section only from the third forward slash.

/post/87/javascript-preview-pdf?id=123&type=article

Once you get the request url, you may also need the different parts of the url to make routing decisions — for example some routes may depend on the GET parameters in the url.

You can use the URL object to get various parts of the url. The URL object needs to be imported from a different built-in module.

const http = require('http');
const url = require('url');

const server = http.createServer((request, response) => {
    const current_url = new URL(request.url);
    const pathname = current_url.pathname;
    const search_params = current_url.searchParams;
}); 

The pathname and search query of a url can be found with the pathname and searchParams properties of the URL object.

You can also get the query parameters (GET parameters) using the has and get methods of the URLSearchParams object.

const current_url = new URL(request.url);
const pathname = current_url.pathname;

// a URLSearchParams object
const search_params = current_url.searchParams;

// check whether "id" parameter exists in the url
if(search_params.has('id')) {
    // value of "id" parameter
    const id = search_params.get('id');
}

if(search_params.has('type')) {
    const page_type = search_params.get('type');
}

The URL object is browser compatible too — it can also be used in the frontend Javascript of web applications. See How to Get URL Parameters with Javascript for more.

Routing Decisions

Once you get the HTTP method and the various parts of the incoming url, routing can be done.

const server = http.createServer((request, response) => {
    const method = request.method;
    const current_url = new URL(request.url);
    const pathname = current_url.pathname;
    const search_params = current_url.searchParams;

    if(method === 'GET' && pathname === '/posts' && !search_params.has('id')) {
        // GET request to /posts
    }
    else if(method === 'GET' && pathname === '/posts' && search_params.has('id')) {
        // GET request to /posts?id=123
    }
    else if(method === 'POST' && pathname === '/posts') {
        // POST request to /posts
    }
});