DEV Community

Cover image for Routinejs, An Express inspired blazingly fast Nodejs router
Zulfiqar Ali
Zulfiqar Ali

Posted on • Edited on

Routinejs, An Express inspired blazingly fast Nodejs router

Hello there,
I am here to introduce you to Routine, An Express inspired and compatible Nodejs router.

Documentation is still a work in progress but the core framework api is stable and ready to use.
Please consider leaving a star at Routine's Github repo

Some high level features of Routine

✅ It is 5 times faster than Express (benchmark code is also available within the repo)
✅ Typescript support is built-in
✅ Radix trie based router
✅ Supports regex as url-path
✅ Middleware and nested route support
✅ Supports almost all existing Expressjs plugins/middlewares
✅ Built-in body parser and cookie-parser
✅ Built in json responder using fast-safe-stringify which is faster than native JSON.stringify and also detects circular objects

Benchmark comparing Routine with Express and Hapi, Koa was also tested but it failed to process so many requests and kept giving ERPIPE error, You can run these benchmarks yourself as well, simply refer to the benchmarks folder within the repo

Benchmarks

Code examples below are also available on CodeSandbox here

Let's start with a simple Hello World example in Typescript

//Importing Routine class along with some types
import Routine, { Request, Response } from "@juniordev/routinejs";

//Creating a new instance of Routine
const app = new Routine();

//Registering a GET route on path '/'
app.get(`/`, (req: Request, res: Response) => {
  res.json({
    msg: "Hello Routine"
  });
});

//Starting the server on PORT 8080, default port is also 8080
app.listen(8080);
Enter fullscreen mode Exit fullscreen mode

This starts the server at http://localhost:8080 and when we visit this url, we receive {"msg": "Hello Routine"} since we have a GET route registered at / path.

Note: The built-in .json method uses fast-safe-stringify which is faster than native JSON.stringify and also detects and prevents [Circular] Object within Response, So it is highly recommended to use this method for sending json payload to client.

Let's have a look at POST route

//Importing Routine class along with some types
import Routine, { Request, Response } from "@juniordev/routinejs";

//Creating a new instance of Routine
const app = new Routine();

//Registering a GET route on path '/'
app.get(`/`, (req: Request, res: Response) => {
  res.json({
    msg: "Hello Routine"
  });
});

//Registering a POST route also on path `/`
app.post(`/`, (req: Request, res: Response) => {
  //Automatic request body parsing without any plugin  
  //Sending the request body back to the client
  res.json(req.body);
});

//Starting the server on PORT 8080, default port is also 8080
app.listen(8080);
Enter fullscreen mode Exit fullscreen mode

This time, we receive whatever we send as body to the server, if we send {"msg": "Hello Routine"} as JSON payload to the server, we receive {"msg": "Hello Routine"} back.

Routine has all major http verbs built-in, such as
GET, POST, PUT, PATCH and DELETE

Named & Query Params

//Importing Routine class along with some types
import Routine, { Request, Response } from "@juniordev/routinejs";

//Creating a new instance of Routine
const app = new Routine();

//Registering a GET route on path '/:name'
app.get(`/:name`, (req: Request, res: Response) => {
  res.json({
    name: req.params.name,
    query: req.query
  });
});

//Starting the server on PORT 8080, default port is also 8080
app.listen(8080);
Enter fullscreen mode Exit fullscreen mode

Visiting http://localhost:8080/routine?hello=world would return us

{
  "name": "routine",
  "query": {
    "hello": "world"
  }
}
Enter fullscreen mode Exit fullscreen mode

Note: You can put any valid regex as path and routine will try to match it

Using middlewares

//Registering a middleware
app.use((req: Request, res: Response, next: NextFunction) => {
  console.log("middleware called");
  next();
});
Enter fullscreen mode Exit fullscreen mode

Middleware functionality is same as Express, that is why Routine is almost fully compatible with Express plugins, and is tested with popular ones such as Morgan, Express Validator etc

Lastly, let's see how nested routes are implemented

//src/router.ts
import { Router, Request, Response } from "@juniordev/routinejs";

const router = new Router();

router.get(`/router`, (req: Request, res: Response) => {
  res.json({
    msg: "from router"
  });
});

export default router;
Enter fullscreen mode Exit fullscreen mode
//src/index.ts
import Routine, { NextFunction, Request, Response } from "@juniordev/routinejs";
import router from "./router";

//Creating a new instance of Routine
const app = new Routine();

//Using a nested router
app.use(`/nested`, router);

app.listen(8080)
Enter fullscreen mode Exit fullscreen mode

When we visit http://localhost:8080/nested/router, server returns {"msg":"from router"}

All the above http methods, named or query params, middlewares can also be applied to nested routes as well, even so much so that nested routes can have more nested routes, and it does NOT degrade route matching performance due to startup/compile time route compilation

This was a basic introduction to Routine, many features such as cancel function, global async error handling etc is not yet talked about, but will be covered in future posts, you can read the docs for async error handling caveats for now though, its a good read i promise :)

Top comments (0)