file-routing-expressjs
Version:
A dependency-free, flexible, system-based file routing for Express.
295 lines (219 loc) • 10 kB
Markdown
# file-routing-expressjs
A dependency-free, flexible, system-based file routing for Express.
## Installation
```shell
npm install file-routing-expressjs
```
## Usage
This package integration in your project is very simple. You will need to wrap your `Express` instance with an `mapRoutes(config)` that will bind the routes directly to the app.
```js
import express from "express";
import path from "path";
import { mapRoutes } from "file-routing-expressjs";
const ROUTES_PATH = path.resolve(__dirname, "..", "app", "routes");
const app = express();
// Option 1: Basic usage
mapRoutes({app: app, target: ROUTES_PATH})
// Option 2: If you need to log the endpoints binded by mapRoutes use this
async function main() {
const { endpoints } = await mapRoutes({app: app, target: ROUTES_PATH});
console.table(endpoints);
}
main();
app.listen(3000, ()=> console.log("I'm listening mother father"));
```
### Options
- **`target`**: The root directory for your route files. Defaults to `/src/routes`.
- **`app`**: The instance of the **Express** application used for handling routes.
## Routes Directory Structure
Files located in your project's `options.target` directory will automatically correspond to a matching URL path.
**Note**: Files that start with an underscore (`_`) or do not have a `.ts` or `.js` extension will not be bound to the app.
```
📦routes
┣ 📂api
┃ ┗ 📜index.ts
┃ ┗ 📜_middleware.ts # global middlewares for '/api'
┣ 📂[users] # dynamic params
┃ ┣ 📂[user]
┃ ┃ ┣ 📜index.ts
┃ ┣ 📜books.ts
┃ ┣ 📜index.ts
┃ ┣ 📜_middleware.ts
┃ ┣ 📜_error.ts
┃ ┗ 📜_config.ts # /:users config file (path pattern etc.)
┣ 📜index.ts # '/' endpoint - default route
┣ 📜posts.ts # '/posts' endpoint
┣ 📜_error.ts # global error handler
```
The folder structure is quite simple and straightforward, as you can see. 💀💀💀
* `/api/<?pattern_in_index>`
* `/:users<?patter_in_config>/<?pattern_in_index>`
* `/:users<?patter_in_config>/books<?pattern_in_books>`
* `/:users<?patter_in_config>/:user/<?pattern_in_index>`
* `/<?pattern_in_index>`
* `/posts<?pattern_in_posts>`
## Examples
### HTTP Method Handling
If you export functions such as `get`, `post`, `put`, `patch`, `all` or `delete` from a route file, they will automatically be mapped to their respective `HTTP/Express` methods .
```js
export const _get = (req, res, next) => {...}
export const _post = (req, res) => {...}
export const _delete = (req, res) => {...}
export const _put = (req, res, next) => {...}
export const _patch = (req, res, next) => {...}
export const _all = (req, res, next) => {...}
```
### Route Pattern
#### For a directory
In the example above, there's a file named `/[users]/_config.ts`. In this file, you should export an object that is used to configure the route pattern for that specific endpoint. This configuration object can include settings like a custom URL pattern or route validation.
```js
// Option 1: default export
export default {
pattern: /[a-fA-F0-9]{24}/g // this could be a Regex or a string
};
// Option 2: named export
export const config = {
pattern:'[a-fA-F0-9]{24}'
};
```
* `/:users([a-fA-F0-9]{24})/<?pattern_in_index>`
If `users` path is not a dynamic route your endpoint will be:
* `/([a-fA-F0-9]{24})/<?pattern_in_index>`
#### For JS/TS files
You can define a global pattern that applies to all HTTP methods in Express routes, or alternatively, specify a distinct pattern for each method within the route file. This allows for flexible URL handling, depending on whether you need a consistent format for all methods or different structures for specific HTTP methods.
```js
// Option 1: a pattern for each method
export const config = {
pattern: {
get: /[A-Z]{3}-[0-9]{4}-[a-z]{2}/,
post: /([0-9]{5})/,
put: /[A-Z]{2}[0-9]{2}/
delete: /(^\d{5}(-\d{4})?$)/,
patch: /(^([01]\d|2[0-3]):([0-5]\d)$)/,
all: /^\d{13,19}$/
}
}
// Option 2: a global pattern
export const config = {
pattern: /[A-Z]{3}-[0-9]{4}-[a-z]{2}/
}
```
#### Option 1
| method | endpoint |
| ---------- | --------------------------------------------------------- |
| **GET** | `/:users([a-fA-F0-9]{24})/([A-Z]{3}-[0-9]{4}-[a-z]{2})` |
| **POST** | `/:users([a-fA-F0-9]{24})/([0-9]{5})` |
| **PUT** | `/:users([a-fA-F0-9]{24})/([A-Z]{2}[0-9]{2})` |
| **DELETE** | `/:users([a-fA-F0-9]{24})/(^\d{5}(-\d{4})?$)` |
| **PATCH** | `/:users([a-fA-F0-9]{24})/(^([01]\d\|2[0-3]):([0-5]\d)$)` |
| **ALL** | `/:users([a-fA-F0-9]{24})/(^\d{13,19}$)` |
**Note**: If you specify an **all** pattern in the configuration object, it will be used as the default pattern for any HTTP methods that are not explicitly defined.
#### Option 2
| method | endpoint |
| ---------------------------------------------------------- | ------------------------------------------------------- |
| **GET**, **POST**, **PUT**, **DELETE**, **PATCH**, **ALL** | `/:users([a-fA-F0-9]{24})/([A-Z]{3}-[0-9]{4}-[a-z]{2})` |
### Middleware
You can apply route-specific middleware in Express by exporting an array of request handlers directly from your route file.
#### For a directory
In the example above, there's a file named `/[users]/_middleware.ts`. In this file, you should export a middleware or the list of middlewares you want to apply on the endpoint (`/users` in this case). The middleware will wrap all the sub routes of `/:users`
```js
import authMiddleware from "../middlewares/authMiddleware";
import rateLimitingMiddleware from "../middlewares/rateLimitingMiddleware";
import testMiddleware from "../middlewares/testMiddleware";
// Option 1: A list of middleware functions
export const middlewares = [
authMiddleware,
rateLimitingMiddleware
testMiddleware
];
// Option 2: A single middlware function
export const middlewares = testMiddleware;
// default export or named export
export default middlewares;
```
#### For JS/TS files
You can define a global middleware/list of middlewares that wraps to all HTTP methods in Express routes, or alternatively, specify a distinct middleware/list of middlewares for each method within the route file.
```js
// Option 1: One middleware for all the exisiting requests handlers
export const middlewares = authMiddleware;
// Option 2: A list of middlewares for all the exisiting requests handlers
export const middlewares = [rateLimitingMiddleware, authMiddleware, testMiddleware];
// Option 3: A map of methods with middlware/list of middlewares
export const middlewares = {
get: [testMiddleware, rateLimitingMiddleware],
all: authMiddleware
};
```
**Note**: Any route handlers that are not explicitly defined will be wrapped by the `all` middleware, if such middleware exists.
### Error Handling
You can apply route-specific middleware in Express by exporting an array of request handlers directly from your route file.
#### For a directory
In the example above, there is a file named `/[users]/_error_.ts`. Within this file, you should export an error handler function, which can be either a default or named export. This function will handle errors specific to `[users]` directory route and the routes under it.
```js
import globalErrorHandler from "../middlewares/globalErrorHandler";
export const errorHandler = globalErrorHandler;
// default export or named export
export default errorHandler;
```
#### For JS/TS files
You can define an error handler that wraps all HTTP methods in Express routes, or alternatively, specify a distinct error handler for each method within the route file.
```js
import testErrorHandler from "../middlewares/testErrorHandler";
import clientErrorHandler from "../middlewares/clientErrorHandler";
// Option 1: A handler fro all the existing methods
export const error = clientErrorHandler;
// Option 2: A map of methods with error handlers
export const error = {
put: testErrorHandler,
all: clientErrorHandler
};
```
**Note**: Any route handlers that are not explicitly defined will be wrapped by the `all` error handler, if such error handler exists.
### Examples - TS
#### For a directory
##### `_config.ts`
```ts
import { DirRouteConfig } from "file-routing-expressjs";
const config: DirRouteConfig = {
pattern: "[A-Z]{2}-\\d{4}"
};
export default config;
```
##### `_middleware.ts`
```ts
import { RouterDirMiddleware } from "file-routing-expressjs";
import authMiddleware from "../middlewares/authMiddleware";
import testMiddleware from "../middlewares/testMiddleware";
export const middlewares: RouterDirMiddleware = [
authMiddleware,
testMiddleware
];
```
##### `_error.ts`
```ts
import { ErrorHandler } from "file-routing-expressjs";
import errorsMiddleware from "../middlewares/errorsMiddleware";
export const errorHandler: ErrorHandler = errorsMiddleware;
```
#### For JS/TS files
```ts
import { RequestHandler } from "express";
import { RouterFileMiddleware, RouterFileError, RouteConfig } from "file-routing-expressjs";
import testMiddleware from "../../middlewares/testMiddleware";
import authMiddleware from "../../middlewares/authMiddleware";
import clientErrorHandler from "../../middlewares/clientErrorMiddlware";
export const config: RouteConfig = {
pattern: {
get: /[A-Z]{3}-[0-9]{4}-[a-z]{2}/,
all: /[a-fA-F0-9]{24}/
}
};
export const middlewares: RouterFileMiddleware = {
get: testMiddleware,
all: authMiddleware
};
export const error: RouterFileError = clientErrorHandler;
export const _get: RequestHandler = (req, res, next)=> {...}
export const _post: RequestHandler = (req, res, next)=> {...}
export const _put: RequestHandler = (req, res, next)=> {...}
```