fs-router
Use the FS as your micro router
"features"
- ✅ 0 runtime dependencies
- ✅ < 100 loc
- ✅ little or no config
- ✅ parameterized paths
- ✅ parses query string
intent
Micro is a fantastic library, but does not come with a router. After using next.js and really enjoying the "fs as router" paradigm, I thought it might be nice to do the same with micro.
This is the simplest approach I could think of to create a flexible router that stays out of your way with an intuitive API.
usage
router usage
// index.jsconst send = let match = __dirname + '/routes' module { let matched = if matched return await }
The above usage assumes you have a folder called routes
next to the index.js
file, that looks something like this:
routes/
├── foo
│ └── :param
│ └── thing.js
└── things
└── :id.js
the above tree would generate the following routes:
/foo/:param/thing
/things/:id
defining a route
// routes/foo/bar.jsconst send = // respond to specific methods by exposing their verbsmoduleexports { // fs-router decorates your req object with param and query hashes }
path parameters
// routes/foos/:id.jsconst send = // responds to any method at /foos/* (but not /foos or /foos/bar/baz)module { // params are always required when in a path, and the }
works great with async/await
const send json = const qs = moduleexports { const query = qs const data = await const res = await const response = await res }
typescript Use esModuleInterop and commonjs to import
// tsconfig.json "compilerOptions": "module": "commonjs" "esModuleInterop": true ...config
use the RequestHandler
type from this lib
A full typescript example is available in the examples directory
priority
moduleexports { }// all routes are sorted by this property - the higher numbers are matched first.// kind of like a z-index for your routes.// note that equal priority will just sort based on the fs in the case of a collision, which is not guaranteed order on OSX/Linuxmoduleexportspriority = -1
custom path
// routes/whatever.jsmoduleexports { }// exposing a "path" will override the fs-generated one.// This is nice if you wanted to avoid making a really deep tree for a one-off path (like for oauth callbacks)// or if you just want to avoid putting `:` in your file/folder names or somethingmoduleexportspath = '/foo/bar'
index routes
// routes/index.jsmoduleexports { return 'hello!'}// The above route would be reachable at / and /index.// This works for deep paths (/thing/index.js maps to /thing and /thing/index)// and even for params (/thing/:param/index.js maps to /thing/* and /thing/*/index).
filter routes
// index.jsconst send = // set up config to filter only paths including `foo`const config = f !== -1 // pass config to `fs-router` as optional second paramaterlet match = __dirname + '/routes' config module { let matched = if matched return await }
The above usage assumes you have a folder called routes
next to the index.js
file, that looks something like this:
routes/
├── foo
│ ├── index.js
│ └── thing.js
└── bar
├── index.js
├── foo.js
└── thing.js
the above tree would generate the following routes:
/foo
/foo/thing
/bar/foo
Multiple file extensions
// index.jsconst send = // set up the config to both include .js and .ts files.const config = ext: '.js' '.ts' // pass config to `fs-router` as optional second paramaterlet match = __dirname + '/routes' config module { let matched = if matched return await }