DEV Community

Cover image for Build nested routes in nodejs using grandjs
tareksalem
tareksalem

Posted on

Build nested routes in nodejs using grandjs

Hi, it's long time since last article I wrote here about grandjs framework which is a promising nodejs framework for building scalable, maintainable and fast backend web applications, today I came with new amazing feature has been added to grandjs!
Here is the repo of the project on github to fork and contribute us

GitHub logo tareksalem / grandjs

A backend framework for solid web apps based on node.js

Grandjs logo

# Grandjs A backend framework for solid web apps based on node.js

You want to build a solid web application but you don't want to use express and a lot of packages you need to build a basic website, Grandjs is one framework includes all main functionalities you need to build amazing, solid and secured web application without need for a ton of packages and libraries.

  • Grandjs is built for solid and extended web apps

GitHub contributors npm GitHub code size in bytes npm

Prerequisites

1- you need to install node.js on your system 2- init a new project using npm, so then we will be able to install this framework

Features

  • fewer packages and more productivity
  • Framework includes the most needed functionalities to build a perfect web app
  • depends on Handlebars template Engine which is friendly with many developers
  • solid routing system built on Javascript object-oriented programming and you can extend it as you need
  • controlled handling for…

If you tried Grandjs before, maybe you found that grand js is based on OOP and ES6 class implementation to build your routes, as long as you may asked yourself how do you can include router inside router to make the hierarchy of your routes much easier!

so for example we have a basic router that is working on the following url / also we have an admin that it works on /admin, this admin has a lot of routes, such as categories CRUD operation, products CRUD operation and users CRUD operation. At the first time you think may you will implement this scenario inside one router class contains all routes as the following:

const {Router} = require("grandjs");
class AdminRouter extends Grand.Router{
    constructor(props) {
        super(props);
        this.getRouters = [
            this.listCategories.bind(this)(),
            this.indexCategory.bind(this)(),
           this.listPosts.bind(this)()
           this.indexPost.bind(this)()
           this.showUsers.bind(this)()
           this.indexUser.bind(this)()
        ];
        this.postRouters = [
           this.addPost.bind(this)(), 
           this.addCategory.bind(this)(),
           this.addUser.bind(this)(), 
        ];
        this.putRouters = [];
        this.patchRouters = [];
        this.deleteRouters = [];
    }
    listCategories() {
       return {
          url: "/categories",
          method: "GET",
          handler: (req, res) => {
             return res.status(200).json({data: []})
          }
       }
    }
    listUsers() {
       return {
          url: "/users",
          method: "GET",
          handler: (req, res) => {
             return res.status(200).json({data: []})
          }
       }
    }

    listPosts() {
       return {
          url: "/posts",
          method: "GET",
          handler: (req, res) => {
             return res.status(200).json({data: []})
          }
       }
    }
    indexCategory() {
       return {
          url: "/categories/:id",
          method: "GET",
          handler: (req, res) => {
             return res.status(200).json({data: {}})
          }
       }
    }

    indexPost() {
       return {
          url: "/posts/:id",
          method: "GET",
          handler: (req, res) => {
             return res.status(200).json({data: {}})
          }
       }
    }

    indexUser() {
       return {
          url: "/users/:id",
          method: "GET",
          handler: (req, res) => {
             return res.status(200).json({data: {}})
          }
       }
    }

    addCategory() {
       return {
          url: "/category",
          method: "POST",
          handler: (req, res) => {
             console.log(req.data);
          }
       }
    }
    addPost() {
       return {
          url: "/post",
          method: "POST",
          handler: (req, res) => {
             console.log(req.data);
          }
       }
    }
    addUser() {
       return {
          url: "/user",
          method: "POST",
          handler: (req, res) => {
             console.log(req.data);
          }
       }
    }

}

Imagine that all these routes will be inside the same router class, it will be hard to maintain and adding new routes, which will lead you to build separate routes for each feature, so for category routes, you will build a routing class and another routing for posts and the same for users.
Until now everything is fine, but how to add all these routes under /admin base router !!!?
Here is the solution:
Grandjs offers to you a method called useRouter which is a function you can call inside the class or outside it to add new routes to the main class, so simply you will create your routes files that will be added under /admin path and inside admin router you will use useRouter method to add nested routes inside it

//define category routes
class CategoryRouter extends Grand.Router{
   constructor(props) {
      super(props)
   }
}

class PostRouter extends Grand.Router{
   constructor(props) {
      super(props)
   }
}

class AdminRouter extends Grand.Router{
   constructor(props) {
      super(props)
      //use category router
      this.useRouter(CategoryRouter)
      // use post router
      this.useRouter(PostRouter)
   }
}

as you can see above, it's super easy to implement a group of routes inside another router, you can add infinity nested routers without any problem, also you can define a specific base url for each nested router!!
You may ask now How can I add base url for each nested router!!!!
My friend it's super easy in grandjs, what you need is defining the following property inside the class:

this.base = "/nestedbaseurl"

so once you do that, all the routes inside this class will be added to the base however you instantiate this class or use it inside another one!
So if you think about how to apply that on the above example it will be something like that:

//define category routes
class CategoryRouter extends Grand.Router{
   constructor(props) {
      super(props)
      this.base = "/cat"
   }
}

class PostRouter extends Grand.Router{
   constructor(props) {
      super(props)
      this.base = "post"
   }
}

class AdminRouter extends Grand.Router{
   constructor(props) {
      super(props)
      //use category router
      this.useRouter(CategoryRouter)
      // use post router
      this.useRouter(PostRouter)
      this.base = "/admin"
   }
}

each url implemented in admin router will be working in this url /admin/*, and to access category routes will be on the following url /admin/cate/*
and to access post router routes it will work on /admin/post/*.

As you can see, it'super easy to extend your routes, so using grandjs you can write super-extended, extensible and easy to maintain backend application using nodejs.

you can find more examples, and play with grandjs on replit on the following url:

previous tutorials:

Discussion (2)

Collapse
faraazahmad profile image
Syed Faraaz Ahmad

I can simply do app.use('/posts', postRouter) in ExpressJS. What is the benefit of using grandjs?

Collapse
tareksalem profile image
tareksalem Author

this is a good question, express easily can append routes as you explained in the example, but what about if you don't want to add /posts to use another group of routes so simply you want to do something like the following:

adminRouter.use(postRouter)

and also you have for example categories router you want to append to /admin directly so you will have something like the following:following:

adminRouter.use(postRouter)
adminRouter.use(categoriesRouter) 

this will work fine, but what about if you want to add some middlewares on the post router however you don't make these middlewares applied in categories router ??
you will find that all routes in the admin router have the middlewares of a specific router which is an isolation problem, to understand what I mean you can test this example:

This problem is solved in grandjs.
Actually grandjs include a lot of benefits, but this example to elaborate the difference.