Deviopath › Node.js

Router with Route Priority

Hard · Express

Fast Node routers such as find-my-way (used by Fastify) do not just try routes in registration order: they pick the most specific route. At each path segment a static segment beats a :param, and a :param beats a * wildcard. Implement such a router.

class Router has add(method, pattern, name) and find(method, path). Patterns are split on / (empty segments ignored). Each segment is static text, :name (matches exactly one segment and captures it), or * (only as the last segment: matches one or more remaining segments, captured as params["*"] joined with /).

find(method, path) works like this:

1. Drop the query string (from ?). Split on / and ignore empty segments, so a trailing slash does not matter. Decode each segment with decodeURIComponent (so an encoded %2F stays inside its segment). If decoding fails, return { status: 400 }.

2. Collect every route whose pattern matches the path, for any method. If there is none, return { status: 404 }.

3. Rank the matching routes by comparing their segment kinds from left to right. At the first position where the kinds differ, the more specific kind wins (static, then param, then wildcard). Routes with the same kinds keep registration order.

4. Take the best-ranked route whose method equals method. A HEAD request that finds no HEAD route uses the best GET route instead. Return { status: 200, route: name, params }.

5. If the path matched but no route has the method, return { status: 405, allow }. allow lists the methods of all matching routes (plus HEAD when GET is there), without duplicates, sorted alphabetically and joined with ", ". It is the value of the Allow header.

Static segments are compared case-sensitively with the decoded segment. The driver runRouter(routes, requests) is already written: it adds every [method, pattern, name] and returns find(method, path) for every request.

Next: Writable Stream Backpressure