Find My Way HTTP Router
find-my-way is a high-performance HTTP router for Node.js, currently at version 9.5.0, designed for speed using a Radix Tree implementation. It is framework-independent and supports advanced routing features such as route parameters, wildcards, and versioned routes. The project maintains an active release cadence, with recent updates focusing on performance improvements, Node.js version compatibility (requiring Node.js >=20), and security fixes. Key differentiators include its proven speed, demonstrated in benchmarks against other popular routers, and its direct use in major frameworks like Fastify and Restify, indicating robustness and reliability for production environments. It also provides a comprehensive API for route management including `on`, `off`, `findRoute`, `hasRoute`, and `lookup`.
Common errors
-
TypeError: router.lookup is not a function
cause The `find-my-way` module was imported or required but not instantiated correctly. For example, `require('find-my-way')` returns a constructor function, not an instance directly.fixEnsure you instantiate the router after importing/requiring it: `const FindMyWay = require('find-my-way'); const router = FindMyWay();` or `import FindMyWay from 'find-my-way'; const router = new FindMyWay();`. -
Error: Route already registered for method 'GET' with path '/some/path'
cause Attempting to register the same HTTP method and path combination more than once without using constraints (like versioning or host-based routing).fixCheck for duplicate route registrations. If intentional, use constraints (`{ constraints: { version: '1.0.0' } }`) or ensure paths are unique. For example, `router.on('GET', '/path', handler1)` and `router.on('GET', '/path', handler2)` will cause this error. -
404 Not Found (for a path that seems to match a registered route)
cause This often occurs due to trailing slash mismatch. For instance, a route for `/users` won't match a request for `/users/` if `ignoreTrailingSlash` is not enabled.fixInitialize the router with `ignoreTrailingSlash: true` if you want paths with and without trailing slashes to resolve to the same route. Alternatively, register both `/users` and `/users/` explicitly.
Warnings
- breaking The behavior of parameter objects changed in `v9.0.0`. Previously, route parameters might have been regular objects, but they are now 'null objects' (objects created with `Object.create(null)`). This can affect assumptions about prototype chain or methods like `hasOwnProperty` if not accounted for.
- breaking Node.js version requirements were increased in `v9.0.0`, dropping support for older Node.js runtimes. The package now requires Node.js version 20 or higher.
- breaking A security vulnerability (CVE-2024-45813 / GHSA-rrr8-f88r-h8q6) related to a ReDoS (Regular Expression Denial of Service) in multiparametric routes was patched in `v8.2.2` and `v9.0.1`. This could lead to excessive CPU consumption with specifically crafted URLs.
- gotcha By default, `find-my-way` invokes a `defaultRoute` for badly formatted URLs (e.g., `/hello/%world`). If not explicitly handled, this might result in a generic 404.
- gotcha Trailing slashes are not ignored by default. A route registered for `/foo` will not match `/foo/`.
- gotcha Node.js `http.METHODS` was updated in Node 22.2.0 to include 'QUERY'. If running an older Node.js version with routes using 'QUERY', it might not be recognized.
Install
-
npm install find-my-way -
yarn add find-my-way -
pnpm add find-my-way
Imports
- FindMyWay
import { FindMyWay } from 'find-my-way';import FindMyWay from 'find-my-way'; const router = new FindMyWay();
- FindMyWayOptions
import { FindMyWayOptions } from 'find-my-way';import type { FindMyWayOptions } from 'find-my-way'; - CommonJS require
const { FindMyWay } = require('find-my-way');const FindMyWay = require('find-my-way'); const router = FindMyWay();
Quickstart
const http = require('http')
const FindMyWay = require('find-my-way')
const router = FindMyWay()
router.on('GET', '/', (req, res, params) => {
res.end('{"message":"hello world"}')
})
router.on('GET', '/user/:id', (req, res, params) => {
res.end(`{"message":"hello user ${params.id}"}`)
})
router.on('POST', '/data', (req, res) => {
let body = ''
req.on('data', chunk => { body += chunk })
req.on('end', () => {
res.end(`Received data: ${body}`)
})
})
const server = http.createServer((req, res) => {
router.lookup(req, res)
})
server.listen(3000, err => {
if (err) throw err
console.log('Server listening on: http://localhost:3000')
console.log('Try visiting http://localhost:3000 and http://localhost:3000/user/123')
console.log('Or curl -X POST -d "test" http://localhost:3000/data')
})