Creating A NodeJS RESTful API without ExpressJS — Part 3

Adding Nested And Dynamic Routes To The API

Parag Mahale
4 min readMay 8, 2022
Creating A NodeJS RESTful API without ExpressJS — Part 3 — Adding Nested And Dynamic Routes To The API
Adding Nested And Dynamic Routes To The API

In previous articles, we’ve created a NodeJS RESTful API without using ExpressJS or any other NPM packages and added CRUD functionality to it.

In this article, we’ll be improving our API by adding the functionality of Nested Routes and Dynamic Routes.

Creating A NodeJS RESTful API without ExpressJS — File Structure

We won’t be adding or removing any new files in this article.

Creating A NodeJS RESTful API without ExpressJS — Nested & Dynamic Routes

Our previous method for finding out the correct handler was a bit simplistic, resulting in a very unintuitive structure of the router object in router.js, and was unable to handle variable routing.

So, we’ll be changing our router object and the logic for finding the correct handler quite a lot.

In index.js, change

const router = require('./router')

to

const getHandler = require('./router')

getHandler is a function defined in router.js that will return us the correct handler from the router object.

const route = getHandler(pathName, reqMethod)

getHandler requires pathname and reqMethod for finding the correct handler. If the handler is not present, we return the default handler. We’ll see what the default handler is in detail in just a bit.

The rest of the logic for index.js remains the same.

In router.js,

We are going to restructure the router object so the search operation for the handler becomes easier.

In getHandler we will be splitting the path we have received with pathname by using split() method.

If the pathname is /ping/add, the resulting array after split(‘/’) will be,

[‘’, ‘ping’, ‘add’]

So to be consistent with this result, in the router object, we’ll replace ‘/’ with ‘’, and all the remaining routes will be defined in it. ‘notFound’ handler will be its own separate handler.

A small rule we’ll follow in the router object is that the HTTP methods will be declared in capital letters and the paths will be declared in small case letters, so it is easier to distinguish between them.

So the router object in router.js is as follows,

const router = {  '' : {    'GET': handlers.ping,    'POST': handlers.pingPost,    'DELETE': handlers.pingDelete,    'PATCH': handlers.pingUpdate,    'ping' : {      'GET': handlers.ping,      'add':{        'GET': handlers.pingAdd      },      'default':{
'POST': handlers.pingVariable
} }, }, 'notFound': handlers.notFound}

default’ routes are basically dynamic routes. We can declare any handler with any HTTP method in it for it to behave like a dynamic route, or we can just declare it to be a ‘notFound’ handler.

Now, we’ll be implementing the getHandler function.

const getHandler = (path, method) => {  const pathArray = path.split('/')  let reqObject = router  pathArray.forEach(path => {    reqObject = reqObject[path] !== undefined ? reqObject[path] : reqObject['default']  });  if(reqObject === undefined || reqObject[method] === undefined){    return router['notFound']  }else{    return reqObject[method]  }}module.exports = getHandler

Here, we are starting by splitting the path string at ‘/’ and storing it in pathArray. We’ll be searching for each pathArray element.

We are starting our search with the whole router object. As we traverse the pathArray element, we shrink down the router object till we find the object of the last pathArray element. If it exists, we move forward, or else we take the default object.

After we’ve found our required path object, we search for the input method, if any handler is defined for the given HTTP method, we return that handler, otherwise, we return ‘notFound’ handler.

Now to test these features, we’ll define create handlers for them.

In handlers.js,

handlers.pingAdd = async (data, callback) => {  callback(200, {data: 'Hello World From /ping/add'})}handlers.pingVariable = async (data,callback) => {  callback(200, {data: `Variable route at ${data.pathName} with variable ${data.pathName.split('/').pop()}`})}

Creating A NodeJS RESTful API without ExpressJS — Result

For our dynamic routing,

Creating A NodeJS RESTful API without ExpressJS — part 3 — dynamic routing result
dynamic routing result

For nested routing,

Creating A NodeJS RESTful API without ExpressJS — part 3 — nested routing result
nested routing result

And when we try to access an endpoint which is not defined,

Creating A NodeJS RESTful API without ExpressJS — part 3 — handling non exixting endpoints
handling non-existing endpoints

Creating A NodeJS RESTful API without ExpressJS — Final Thoughts

I built this project with an intention of creating an alternative to ExpressJS, which I would use in my other projects, but I don’t think I’ll be using this in place of EpxressJS, as ExpressJS offers much more simplicity and features out of the box.

It was a great learning experience and a fun project to do, as I got to learn so many things about nodeJS and all the pre-built packages it comes with. Frankly, I’ve never used any of the pre-built packages of NodeJS as extensively as on this project.

I had fun!!

--

--