File base routing system for express.js ๐
npm install archipelago
or if you use yarn
yarn add archipelago
import express from 'express';
import archipelago from 'archipelago';
(async () => {
const app = express();
await archipelago(app, {
rootDir: './routes',
// onRouteLoading?: (descriptor) => Promise<void>
// strict?: boolean
});
})();
or using top level await
import express from 'express';
import archipelago from 'archipelago';
const app = express();
await archipelago(app, {
rootDir: './routes'
// onRouteLoading?: (descriptor) => Promise<void>
// strict?: boolean
});
Here are the options you can pass to the archipelago
function:
- [required]
rootDir
: The directory from which to load the routes - [optional]
onRouteLoading
: A function that will be called before a route is loaded - [optional]
strict
: A boolean to indicate if the router should throw an error if a config is not exported by a route file
the special directory _middlewares
allow you to define middlewares that will be applied to the specified routes.
For example, if you want to apply a middleware to all routes in the ./routes/users
directory, you can create a file
./routes/_middlewares/users.ts
with the following content:
export function userMiddleware(req, res, next) {
console.log('before reaching users');
next();
}
export const config = {
routes: [{
method: 'all',
path: "/users",
middlewares: [userMiddleware],
}],
}
The routes will be built based on the path of the file.
For example, if you have a file in ./routes/users.js
, the route will be /users
.
Each route file contains a config object that is exported to be loaded in the router. This config object contains the following properties:
- [optional]
routes
: an array of route descriptors. (here)[./src/types.ts#L14] - [optional]
ignore
: a boolean to ignore the file in case you want to use it to store other functions or utils. (here)[./src/types.ts#L19]
PRIORITY:
The routes are loaded depending on their priority. The routes with the lower number (highest priority) are loaded first. A wilcard route has a priority of Infinity. The smaller number, the higher is the priority.
// ./routes/users/index.ts
export function list(req, res) {
res.send('Hello world');
}
export const config = {
routes: [{
method: 'get',
handlers: [list],
}],
}
this route will be accessible at /users
with the GET
method.
// ./routes/users/[id].ts
export function get(req, res) {
res.send('Hello user ' + req.params.id);
}
export const config = {
routes: [{
method: 'get',
handlers: [get],
}],
}
this route will be accessible at /users/:id
with the GET
method.
// ./routes/users/[id].ts
export function beforeGetAndList(req, res) {
res.send(`Hello user${req.params.id ? ' ' + req.params.id : ''}`);
}
export const config: Config = {
routes: [{
method: 'get',
handlers: [beforeGetAndList],
}],
}
this route will be applied to /users/*
with the GET
method and therefore will be fired before
any subsequent route handler.
In some circumstances, you may want to hook yourself before a route is loading. For example if you want to apply some extra middlewares to a route, or if you want to check and consume the configuration for other purposes.
To do so, you can use the onRouteLoading
hook (the type of the descriptor is available here)
import express from 'express';
import archipelago from 'archipelago';
async function onRouteLoading(descriptor) {
// do something with the descriptor
// ...
// You have access to everything the descriptor contains
// You can find the full types here https://github.com/adrien2p/archipelago/blob/main/src/types.ts
return;
}
const app = express();
await archipelago(app, {
rootDir: './routes',
onRouteLoading,
});
Contributions are welcome! You can look at the contribution guidelines
This project needs a โญ from you. If you really like our projects, do not hesitate to back us