hapi routing algorithm

After learning about hapi's server.route() API and configuration object, you may have found yourself curious as to how is it possible to add all these routes, in a manner that allows to you to keep your codebase manageable. You may have the following questions in mind:

  • Is it possible to have a route conflict?
  • How are routes prioritized and mapped to a request?
  • Is the order in which we register a route relevant?

Don't worry if you didn't have these questions, you'll have them soon enough. But let's answer them now.

hapi is one of the few frameworks in Node that have deterministic routing. Each request can only map to one route, and its routing table will be the same every time you start the server. This was one of the things that appealed to me initially, when I started working with Node and was researching Node frameworks in depth. As the application size and teams grow, routing conflicts become more of a concern, and I wanted to future-proof my work by starting with a framework that had a solid foundation. I found that the deterministic routing of hapi makes for a much more structured, enjoyable, and most importantly, safer approach to application development. If you have two routes that conflict, hapi will show an error on startup, providing details on the routes that conflict, making it much easier to debug and fix. This is much better than spending hours debugging this at runtime. If you have an editor open, I recommend trying to add a conflicting route and starting it so you can see what this error looks like.

This approach to routing is made possible by how hapi processes route definitions on startup. It takes all the route definitions, and creates a routing table where all routes are sorted from being most specific to most generic. You can read more about the path matching order in the API documentation at http://hapijs.com/api#path-matching-order.

When a request is received by the server, the hapi router (which is the call module, https://github.com/hapijs/call) iterates through this sorted routing table to find the first request it matches, and executes only that route.

This approach in routing is very different from that of express, Restify, and other frameworks through node. In those frameworks, routing is not deterministic. In Express, the routing table is organized by the order in which the routes are registered in the code. You can have two routes with the same or similar paths. If a request is received that matches multiple paths, it will execute each matching path.

To compare the two in code would look something like the following.

In hapi, where these if else loops are ordered based on most specific to generic, the code would be as follows:

if(request.match('/path/path1/{id}'/)) {
  return response;
} else if (request.match('/path/path2/{id}')) {
  return response;
} else if (request.match('/path')) {
  return response;
}

In Express, where the order is based on the order registered in the code, the code would be as follows:

if(request.match('/path/path/{id}'/)) {
  return response;
}
if (request.match('/path')) {
  return response;
}
if (request.match('/path/path2/{id}')) {
  return response;
}

These two design philosophies have an interesting trade-off.

With express, non-deterministic routing means that the route patterns can be more flexible, allowing for regular expressions. The downside of this is that the onus is on the developer to ensure that there are no routing conflicts, something which can be quite hard to test.

At this stage, you might notice a recurring theme: when faced with a choice, the design philosophies of hapi always aim to stay on the side of shifting responsibility from the developer to the framework by presenting errors at startup, and giving developers the tools to avoid making unnecessary mistakes.

The following points summarize this section on hapi's path processing:

  • hapi uses deterministic routing
  • problems with route configuration or conflicts will be demonstrated at startup, not at run time
  • routes are sorted from being most specific to most generic, so where server.route() is called in, the code is not important
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.137.75