rg-express
Version:
## User Guide
468 lines (319 loc) β’ 11.8 kB
Markdown
# rg-express
## User Guide
Welcome to the **rg-express** user guide! This document will help you get started with **rg-express**, a powerful route generator for Express that simplifies route management with file-based approach. Whether you're building APIs in TypeScript or JavaScript, **rg-express** provides a clean, intuitive way to organize your routes.
## π Introduction
**rg-express** is a route generator for Express, inspired by the modular routing style of **Next.js**. It helps developers manage routes with cleaner structure, reduced boilerplate, and optional middleware support β all by convention over configuration.
π [Explore the Example Project (TypeScript)](https://github.com/Md-Anamul-Haque/rg-express_example)
## π¦ Installation
Install using your preferred package manager:
```bash
npm install rg-express
# or
pnpm add rg-express
# or
yarn add rg-express
```
## Requirements
- **Express**: `>=5.0.0` is required for compatibility with `rg-express`.
- Make sure you have Express v5 or higher installed.
- Install Express using `npm install express@^5.0.0` , `pnpm add express@^5.0.0` or `yarn add express@^5.0.0`.
- Older versions of Express are not supported.
- For full functionality, ensure your Express version meets the requirement.
## ποΈ Project Structure
### Basic Setup
#### Without `src` Directory
```
βββ package.json
βββ routes/
βββ app.ts or app.js
```
#### With `src` Directory
```
βββ package.json
βββ src/
β βββ routes/
β βββ app.ts or app.js
```
### Inside `routes` Folder
```
routes/
βββ product/
β βββ route.ts β /product
β βββ [slug]/route.ts β /product/:slug β req.params.slug (string)
βββ hello/
β βββ [...slugs]/route.ts β /hello/{*slugs} β req.params.slugs (string[])
```
## βοΈ Basic Usage (Detailed)
rg-express makes it easy to wire up your routes by pointing to a directory. It scans the routes/ folder, maps files to route paths, and either returns an Express Router or attaches routes directly to a provided Express app. The routes function supports both TypeScript and JavaScript projects and can automatically generate starter code for empty route files.
### πΉ Option 1: Minimal Setup (String Path)
The simplest wayβjust provide the root directory where your routes/ folder exists. This returns an Express Router that you can attach to your app.
```ts
// app.ts
import express from 'express';
import { routes } from 'rg-express';
const app = express();
app.use(express.json());
app.use(routes(__dirname)); // Loads routes from __dirname/routes
app.listen(3000, () => {
console.log('π Server running at http://localhost:3000');
});
```
π **Directory structure**
```
project-root/
βββ routes/
β βββ hello/
β βββ route.ts
βββ app.ts
```
π§ In `routes/hello/route.ts`:
```ts
export const GET = (req, res) => {
res.send('Hello world!');
};
```
π Access: `http://localhost:3000/hello`
### πΉ Option 2: Full Configuration (Returning Router)
Provide a configuration object to customize behavior, returning a Router for manual attachment.
```ts
import express from 'express';
import { routes } from 'rg-express';
const app = express();
app.use(
routes({
baseDir: __dirname, // Required: where routes/ folder lives
routeGenIfEmpty: true, // Optional: generates starter code for empty route files
})
);
app.listen(3000, () => {
console.log('β
Server ready at http://localhost:3000');
});
```
### πΉ Option 3: Full Configuration (Attaching to App)
Provide an Express app in the configuration to automatically attach routes to it. This returns void as the routes are directly mounted.
```ts
import express from 'express';
import { routes } from 'rg-express';
const app = express();
routes({
baseDir: __dirname,
routeGenIfEmpty: true,
app, // Attaches routes directly to this app instance
});
app.listen(3000, () => {
console.log('β
Server ready at http://localhost:3000');
});
```
β οΈ **Note**: Passing `app` is deprecated. Prefer returning a `Router` and using `app.use()` for better flexibility.
### πΉ Option 4: Use Default Export
You can use the default `rg` function, which is equivalent to `routes`:
```ts
import express from 'express';
import rg from 'rg-express';
const app = express();
app.use(rg({ baseDir: __dirname }));
```
π This is equivalent to:
```ts
import { routes } from 'rg-express';
app.use(routes({ baseDir: __dirname }));
```
#### β
`RouteConfig` interface options:
| Option | Type | Description |
| ----------------- | --------- | ------------------------------------------------------------------------------- |
| `baseDir` | `string` | **Required.** Root folder (where `routes/` lives) |
| `routeGenIfEmpty` | `boolean` | Auto-generates starter route if file is empty |
| `autoSetup` | `boolean` | β οΈ _Deprecated_ in favor of `routeGenIfEmpty` |
| `app` | `Express` | β οΈ Deprecated. Attaches routes to the app (returns void). Omit to get a Router. |
#### Notes:
- If `autoSetup` is used, a deprecation warning is logged, recommending `routeGenIfEmpty`.
- `routeGenIfEmpty` only works if the projectβs file extension (`.ts`, `.js`, `.mjs`, or `.mts`) matches the project type (TypeScript or JavaScript). For TypeScript projects, it requires `.ts` or `.mts` files.
- The `routes` function validates file extensions, supporting only `.ts`, `.js`, `.mjs`, or `.mts`.
## π‘ Pro Tips
Maximize `rg-express` with these best practices for organizing and scaling your Express projects:
- **Use a** `src/` **Structure**: Place your entry point (e.g., `src/main.ts`) and routes (`src/routes/*/**`) in a `src/` folder for a clean layout. Since `main.ts` is in `src/`, set `baseDir` to `__dirname`:
```ts
import { routes } from 'rg-express';
import express from 'express';
const app = express();
app.use(routes({ baseDir: __dirname }));
```
π **Example Structure**:
```
βββ src/
β βββ routes/
β β βββ api/
β β β βββ [id]/route.ts β /api/:id
β β βββ hello/route.ts β /hello
β βββ main.ts
```
- **Enable Auto-Generation**: Set `routeGenIfEmpty: true` to create starter code for empty route files in `src/routes/`βgreat for rapid prototyping:
```ts
app.use(routes({ baseDir: __dirname, routeGenIfEmpty: true }));
```
This generates templates for new routes, requiring `.ts` for TypeScript or `.js`/`.mjs` for JavaScript.
- **Avoid Deprecated Options**: Skip `autoSetup` and `app` in `routes()`. Return a `Router` and use `app.use()` for modularity:
```ts
const router = routes({ baseDir: __dirname });
app.use('/api', router); // Mount at /api
```
- **Debug with Logs**: Use `rg-express` logs (e.g., "β Ready in") to troubleshoot route scanning or auto-generation in `src/routes/`.
## π Bonus: What Happens Under the Hood?
Given `baseDir = __dirname`:
- **Folder Scanning**: Looks for a `routes/` folder inside `baseDir`.
- **File Matching**: Matches files named `route.ts`, `route.js`, `route.mjs`, or `route.mts`.
- **Route Mapping**: Converts folder structures to Express routes:
- `routes/product/route.ts` β `/product`
- `routes/product/[id]/route.ts` β `/product/:id`
- `routes/hello/[...slugs]/route.ts` β `/hello/{*slugs}`
- **Auto-Generation**: If `routeGenIfEmpty` is `true`, generates starter code for empty route files (only if the file extension matches the project type).
- **HTTP Methods**: Supports standard HTTP methods (`GET`, `POST`, `PUT`, `DELETE`, etc.) exported from route files.
- **Performance Logging**: Logs processing time and completion status using `ProcessConsole`.
## βοΈ Route Configuration
Define HTTP handlers (`GET`, `POST`, etc.) by exporting them from route files. The `routes` function automatically maps these to the corresponding Express routes.
### TypeScript Example
```ts
// routes/hello/route.ts
import type { Request, Response } from 'express';
/**
* @api_endpoint: /hello/
*/
export const GET = (req: Request, res: Response) => {
res.send('Hello from rg-express!');
};
// With middleware
export const POST = [
checkAuth, // your middleware
(req: Request, res: Response) => {
res.send('Posted with middleware!');
},
];
```
### JavaScript Example
```js
// routes/hello/route.js
module.exports.GET = (req, res) => {
res.send('Hello from rg-express!');
};
const handlePost = (req, res) => {
res.send('Posted with middleware!');
};
module.exports.POST = [checkAuth, handlePost];
```
## π Dynamic Routing
### `[slug]` β Single Dynamic Segment
```ts
// routes/abc/[slug]/route.ts
export const GET = (req: Request, res: Response) => {
res.send(`Slug: ${req.params.slug}`);
};
```
β
Matches: `/abc/apple`, `/abc/banana`
### `[...slugs]` β Catch-All Segment
```ts
// routes/abc/[...slugs]/route.ts
export const GET = (req: Request, res: Response) => {
res.send(`Slugs: ${req.params.slugs.join(', ')}`);
};
```
β
Matches: `/abc/a`, `/abc/a/b/c`
---
## π‘οΈ Smart Middleware Support
Export an array to include Express middlewares before your handler:
### Example with Middlewares
```ts
// routes/user/route.ts
import { Request, Response, NextFunction } from 'express';
import { auth, isAdmin } from '../../middlewares';
const getUsers = (req: Request, res: Response) => {
res.send('List of users');
};
const createUser = (req: Request, res: Response) => {
res.send('User created!');
};
export const GET = [auth, getUsers];
export const POST = [auth, isAdmin, createUser];
```
Or define inline handlers:
```ts
// routes/user/route.ts
export const POST = [
auth,
isAdmin,
(req: Request, res: Response) => {
res.send('User created with inline handler');
},
];
```
## π§ Dynamic Routes
### `[slug]` β Single Param
```ts
// routes/blog/[slug]/route.ts
export const GET = (req: Request, res: Response) => {
const { slug } = req.params;
res.send(`You requested blog: ${slug}`);
};
```
## π§± JavaScript Support
```js
// routes/hello/route.js
module.exports.GET = (req, res) => {
res.send('Hello from JavaScript!');
};
module.exports.POST = [
checkAuth,
(req, res) => {
res.send('Post with middleware in JS!');
},
];
```
## π§© Middleware Utilities
You can create reusable middleware functions like:
```ts
// middlewares/index.ts
import { Request, Response, NextFunction } from 'express';
export const auth = (req: Request, res: Response, next: NextFunction) => {
if (!req.headers.authorization) {
return res.status(401).send('Unauthorized');
}
next();
};
export const isAdmin = (req: Request, res: Response, next: NextFunction) => {
if (req.headers['x-role'] !== 'admin') {
return res.status(403).send('Forbidden');
}
next();
};
```
Then reuse them smartly in routes.
## π€ Contributing
We welcome contributions! Please read the CONTRIBUTING.md for details on submitting PRs or reporting issues.
## π Conclusion
`rg-express` makes route organization in Express apps easier, cleaner, and more modular with built-in support for:
- β
TypeScript & JavaScript (`.ts`, `.js`, `.mjs`, `.mts`)
- π§ Dynamic routes
- π§© Express-style middleware
- β‘ File-based auto-loading
- π Automatic starter code generation for empty files
> Build smarter APIs, faster.