{"id":13715981,"url":"https://github.com/jesseditson/fs-router","last_synced_at":"2025-04-06T13:10:14.345Z","repository":{"id":14272017,"uuid":"76198991","full_name":"jesseditson/fs-router","owner":"jesseditson","description":"Use the FS as your micro router","archived":false,"fork":false,"pushed_at":"2022-12-09T08:13:54.000Z","size":495,"stargazers_count":165,"open_issues_count":12,"forks_count":19,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-30T11:09:55.290Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jesseditson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-12-11T20:47:02.000Z","updated_at":"2025-03-06T21:06:49.000Z","dependencies_parsed_at":"2023-01-13T17:51:46.425Z","dependency_job_id":null,"html_url":"https://github.com/jesseditson/fs-router","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jesseditson%2Ffs-router","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jesseditson%2Ffs-router/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jesseditson%2Ffs-router/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jesseditson%2Ffs-router/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jesseditson","download_url":"https://codeload.github.com/jesseditson/fs-router/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247485287,"owners_count":20946398,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T00:01:05.737Z","updated_at":"2025-04-06T13:10:14.322Z","avatar_url":"https://github.com/jesseditson.png","language":"JavaScript","funding_links":[],"categories":["Modules"],"sub_categories":["Routing"],"readme":"# fs-router\nUse the FS as your micro router\n[![Build Status](https://travis-ci.org/jesseditson/fs-router.svg?branch=master)](https://travis-ci.org/jesseditson/fs-router)\n[![Coverage Status](https://coveralls.io/repos/github/jesseditson/fs-router/badge.svg?branch=master)](https://coveralls.io/github/jesseditson/fs-router?branch=master)\n[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)\n\n### \"features\"\n\n- ✅ 0 runtime dependencies\n- ✅ \u003c 100 loc\n- ✅ little or no config\n- ✅ parameterized paths\n- ✅ parses query string\n\n### intent\n\n[Micro](https://github.com/zeit/micro) is a fantastic library, but does not come with a router.\nAfter using [next.js](https://github.com/zeit/next.js) and really enjoying the \"fs as router\" paradigm, I thought it might be nice to do the same with micro.\n\nThis is the simplest approach I could think of to create a flexible router that stays out of your way with an intuitive API.\n\n### usage\n\n**router usage**\n```javascript\n// index.js\nconst { send } = require('micro')\nlet match = require('fs-router')(__dirname + '/routes')\n\nmodule.exports = async function(req, res) {\n  let matched = match(req)\n  if (matched) return await matched(req, res)\n  send(res, 404, { error: 'Not found' })\n}\n```\n\nThe above usage assumes you have a folder called `routes` next to the `index.js` file, that looks something like this:\n```\nroutes/\n├── foo\n│   └── :param\n│       └── thing.js\n└── things\n    └── :id.js\n```\n\nthe above tree would generate the following routes:\n```\n/foo/:param/thing\n/things/:id\n```\n\n**defining a route**\n```javascript\n// routes/foo/bar.js\nconst { send } = require('micro')\n\n// respond to specific methods by exposing their verbs\nmodule.exports.GET = async function(req, res) {\n  // fs-router decorates your req object with param and query hashes\n  send(res, 200, { params: req.params, query: req.query })\n}\n```\n\n**path parameters**\n```javascript\n// routes/foos/:id.js\nconst { send } = require('micro')\n\n// responds to any method at /foos/* (but not /foos or /foos/bar/baz)\nmodule.exports = async function(req, res) {\n  // params are always required when in a path, and the\n  send(res, 200, { id: req.params.id })\n}\n```\n\n**works great with async/await**\n```javascript\nconst { send, json } = require('micro')\nconst qs = require('querystring')\nrequire('isomorphic-fetch')\n\nmodule.exports.GET = async function(req, res) {\n  const query = qs.stringify(req.query)\n  const data = await json(req)\n  const res = await fetch(`http://some-url.com?${query}`)\n  const response = await res.json()\n  send(res, 200, response)\n}\n```\n\n**typescript**\nUse esModuleInterop and commonjs to import\n\n```javascript\n// tsconfig.json\n{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"esModuleInterop\": true,\n    ...config\n  }\n}\n```\n\nuse the `RequestHandler` type from this lib\n```typescript\nimport { RequestHandler } from 'fs-router'\n\nexport const GET: RequestHandler = async (req, res) =\u003e {\n    // req.params and req.query will be typed correctly\n    send(res, 200, { params: req.params, query: req.query })\n}\n```\n\nA full [typescript example](examples/typescript) is available in the [examples directory](examples)\n\n**priority**\n```javascript\nmodule.exports.GET = async function(req, res) {\n  send(res, 200, {})\n}\n// all routes are sorted by this property - the higher numbers are matched first.\n// kind of like a z-index for your routes.\n// note that equal priority will just sort based on the fs in the case of a collision, which is not guaranteed order on OSX/Linux\nmodule.exports.priority = -1\n```\n\n**custom path**\n```javascript\n// routes/whatever.js\nmodule.exports.GET = async function(req, res) {\n  send(res, 200, {})\n}\n// exposing a \"path\" will override the fs-generated one.\n// This is nice if you wanted to avoid making a really deep tree for a one-off path (like for oauth callbacks)\n// or if you just want to avoid putting `:` in your file/folder names or something\nmodule.exports.path = '/foo/bar'\n```\n\n**index routes**\n```javascript\n// routes/index.js\nmodule.exports.GET = async function(req, res) {\n  return 'hello!'\n}\n// The above route would be reachable at / and /index.\n// This works for deep paths (/thing/index.js maps to /thing and /thing/index)\n// and even for params (/thing/:param/index.js maps to /thing/* and /thing/*/index).\n```\n\n**filter routes**\n```javascript\n// index.js\nconst { send } = require('micro')\n\n// set up config to filter only paths including `foo`\nconst config = {filter: f =\u003e f.indexOf('foo') !== -1}\n\n// pass config to `fs-router` as optional second paramater\nlet match = require('fs-router')(__dirname + '/routes', config)\n\nmodule.exports = async function(req, res) {\n  let matched = match(req)\n  if (matched) return await matched(req, res)\n  send(res, 404, { error: 'Not found' })\n}\n```\n\nThe above usage assumes you have a folder called `routes` next to the `index.js` file, that looks something like this:\n```\nroutes/\n├── foo\n│   ├── index.js\n│   └── thing.js\n└── bar\n    ├── index.js\n    ├── foo.js\n    └── thing.js\n```\n\nthe above tree would generate the following routes:\n```\n/foo\n/foo/thing\n/bar/foo\n```\n\n**Multiple file extensions**\n```javascript\n// index.js\nconst { send } = require('micro')\n\n// set up the config to both include .js and .ts files.\nconst config = {ext: ['.js', '.ts']}\n\n// pass config to `fs-router` as optional second paramater\nlet match = require('fs-router')(__dirname + '/routes', config)\n\nmodule.exports = async function(req, res) {\n  let matched = match(req)\n  if (matched) return await matched(req, res)\n  send(res, 404, { error: 'Not found' })\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjesseditson%2Ffs-router","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjesseditson%2Ffs-router","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjesseditson%2Ffs-router/lists"}