@dcefram/fs-routes

Polka/Express routing based on the folder structure. Inspired by ZEIT Now's Serverless Functions structure/workflow.

Usage no npm install needed!

<script type="module">
  import dceframFsRoutes from 'https://cdn.skypack.dev/@dcefram/fs-routes';
</script>

README

fs-routes

Inspired by Vercel's Nextjs approach to pages. Also inspired by the "original" fs-router for Micro.

I initially made this for Polka, but it also worked for my newer fastify-based projects when that became a thing.

Features

  • Structure route handlers like serverless functions/lambdas
  • Zero dependencies
  • Zero configuration
  • Path segments

Installation

npm i @dcefram/fs-routes

Usage

In your entry file where you created your fastify, polka, or express app:

import Fastify from "fastify";
import fsRoutes from "@dcefram/fs-routes";
const fastify = Fastify({ logger: true });

fsRoutes(fastify, "/routes").listen(process.env.PORT, (error) => {
  if (error) throw error;

  console.log(`API Server running at port ${process.env.PORT}`);
});

Folder structure of your app:

your-app
├── index.js # assuming that this is where you initialized your fastify app
└── routes
    └── user
        ├── [slug]
        │   ├── images.js
        │   └── comments.js
        └── [slug].js

Each routes file should have a module.exports that exports an object that contains the handlers. Here's an example:

const httpErrors = require("http-errors");

module.exports = {
  get: (request, reply) => {
    const { slug } = req.params;
    reply.send({ slug });
  },
  put: (request, reply) => {
    reply.send(httpErrors.NotImplemented());
  },
  delete: (request, reply) => {
    reply.send(httpErrors.NotImplemented());
  },
};

It could also export the handlers using the ESM format:

// OR export
export function get(request, reply) {
  const { slug } = req.params;
  reply.send({ slug });
}

export function put(request, reply) {
  reply.send(httpErrors.NotImplemented());
}

export function delete(request, reply) {
  reply.send(httpErrors.NotImplemented());
}

With the folder structure above, you'll get the following endpoints:

GET /user/:slug
PUT /user/:slug
DELETE /user/:slug
GET /user/:slug/images # assuming that images.js has only `get` exported
GET /user/:slug/comments # assuming that comments.js has only `get` exported

### Ignore Files

By default, fs-routes will ignore all files that is prefixed with an underscore (`_`). Example:

```bash

your-app
├── index.js
└── routes
    └── user
        ├── _helpers        # This folder will be ignored
        │   └── some-reusable-logic.js
        ├── [slug]
        │   ├── images.js
        │   ├── comments.js
        │   └── _utils.js    # This file will be ignored
        └── [slug].js

You can overwrite the ignore pattern, and supply it with your own. Example:

import Fastify from "fastify";
import fsRoutes from "@dcefram/fs-routes";

const fastify = Fastify({ logger: true });
const ignorePattern = "\\.internal\\."; // Will ignore files and folders with ".internal." in its name

fsRoutes(fastify, "/routes", { ignorePattern }).listen(
  process.env.PORT,
  (error) => {
    if (error) throw error;

    console.log(`API Server running at port ${process.env.PORT}`);
  }
);

Why make this?

I liked how easy it was to navigate through a Next.js-based project. But there are times that we simply want to ship a pure Node.js API without the frontend, and this is one of the building blocks that I made to make sure that I stay happy building the project.