@chaeco/route-wizard
v0.0.7
Published
File-based automatic route registration for Node.js frameworks
Maintainers
Readme
@chaeco/route-wizard
File-based automatic route registration for Node.js frameworks with zero configuration. Stop manually registering routes and let your file structure do the work!
✨ Features
- 📁 File-driven routing: Automatically generate routes from file structure with zero configuration
- 🏗️ Multi-framework support: Extensible design supporting Express, Koa, Hoa.js, Hono, Fastify, and NestJS
- 📝 Full TypeScript support: Complete type definitions for better development experience
- ⚡ High performance: Synchronous scanning with zero runtime overhead
- 🧩 Framework agnostic: Works with any Node.js framework that supports route registration
- 🎯 Convention over configuration: Sensible defaults with extensive customization options
- 🛡️ Production ready: Comprehensive test coverage and battle-tested in production
- 🔄 Dynamic parameters: Support for nested and optional parameters
🚀 Installation
npm install @chaeco/route-wizard🎯 Quick Start
1. Create controller files
Create route files in the controllers directory:
// controllers/users/get.ts
export default async (req, res) => {
const users = await db.users.findMany();
res.json(users);
};
// controllers/users/post.ts
export default async (req, res) => {
const user = await db.users.create({ data: req.body });
res.json(user);
};
// controllers/users/[id]/get.ts
export default async (req, res) => {
const user = await db.users.findUnique({
where: { id: req.params.id },
});
res.json(user);
};2. Register routes
import express from 'express';
import { registerRoutes } from '@chaeco/route-wizard';
const app = express();
app.use(express.json());
// Register routes - that's it!
registerRoutes(app, {
dir: './controllers',
prefix: '/api', // optional
});
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});3. Your routes are ready
GET /api/users # List all users
POST /api/users # Create user
GET /api/users/:id # Get user by ID
PUT /api/users/:id # Update user
DELETE /api/users/:id # Delete user📁 File Convention
Route-wizard uses a clean, intuitive file structure with support for both folder-based and filename-based routing:
Folder-based (legacy)
controllers/
├── users/
│ ├── get.ts # GET /users
│ ├── post.ts # POST /users
│ └── [id]/
│ ├── get.ts # GET /users/:id
│ ├── put.ts # PUT /users/:id
│ └── delete.ts # DELETE /users/:id
├── users/
│ └── [userId]/
│ └── posts/
│ ├── get.ts # GET /users/:userId/posts
│ └── [postId]/
│ └── get.ts # GET /users/:userId/posts/:postId
└── search/
└── [[query]]/
└── get.ts # GET /search/:query?Filename-based (recommended for deep nesting)
controllers/
├── users.get.ts # GET /users
├── users.post.ts # POST /users
├── users.[id].get.ts # GET /users/:id
├── users.[id].put.ts # PUT /users/:id
├── users.[id].delete.ts # DELETE /users/:id
├── users.[userId].posts.get.ts # GET /users/:userId/posts
├── users.[userId].posts.[postId].get.ts # GET /users/:userId/posts/:postId
└── search.[[query]].get.ts # GET /search/:query?Parameter Types
[param]→:param(required parameter)[[param]]→:param?(optional parameter)
Module Format Support
Route-wizard supports both ES6 and CommonJS module formats:
ES6 Format (recommended):
// controllers/users/get.ts
export default async (req, res) => {
const users = await db.users.findMany();
res.json(users);
};CommonJS Format:
// controllers/users/get.js
module.exports = async (req, res) => {
const users = await db.users.findMany();
res.json(users);
};Both formats are fully supported and can be mixed in the same project.
🔧 Advanced Usage
Middleware Support
Route Wizard supports per-route middleware configuration. You can attach middleware to routes that will be executed before the handler:
// controllers/users/get.ts
export default {
handler: async (req, res) => {
const users = await db.users.findMany();
res.json(users);
},
middlewares: [authenticate, authorize('admin')],
};Or with folder-based routing:
// controllers/api/users/get.ts
const authenticate = (req, res, next) => {
if (!req.headers.authorization) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
};
const handler = async (req, res) => {
const users = await db.users.findMany();
res.json(users);
};
export default { handler, middlewares: [authenticate] };Performance Monitoring
Monitor your route scanning and request performance:
import express from 'express';
import { registerRoutes, PerformanceMonitor, createRouteWizard } from '@chaeco/route-wizard';
const app = express();
// Option 1: Pass existing monitor
const monitor = new PerformanceMonitor();
registerRoutes(app, {
dir: './controllers',
performanceMonitor: monitor,
});
// Get metrics
const metrics = monitor.getMetrics();
console.log(`Route scan time: ${metrics.routeScanTime}ms`);
console.log(`Total requests: ${metrics.totalRequests}`);
console.log(`Cache hit rate: ${(metrics.cacheHitRate * 100).toFixed(1)}%`);
// Get summary
console.log(monitor.getMetricsSummary());
// Option 2: Use route wizard with built-in monitoring
const wizard = createRouteWizard({
dir: './controllers',
enableMonitoring: true,
});
wizard.register(app);
// Access metrics from wizard
const metrics = wizard.getMetrics();
console.log(metrics?.routeScanTime);PerformanceMonitor API
recordRouteScan(duration: number): Record a route scanning operationrecordRequest(responseTime: number): Record a request with response timerecordCacheHit(): Record a successful cache hitrecordCacheMiss(): Record a cache missgetMetrics(): Get current performance metricsgetMetricsSummary(): Get a formatted summary stringreset(): Reset all metrics
Custom Separator
You can customize the separator used in filename-based routing:
registerRoutes(app, {
dir: './controllers',
separator: '_', // Use underscore instead of dot
});With underscore separator:
controllers/
├── api_users.get.ts # GET /api/users
├── users_[id].get.ts # GET /users/:id
└── users_[id]_posts.get.ts # GET /users/:id/postsDepth Limiting
Limit the maximum route depth to prevent overly complex URLs:
registerRoutes(app, {
dir: './controllers',
maxDepth: 3, // Maximum 3 path segments
});Routes exceeding the depth limit will be ignored.
Multiple Parameters
// controllers/users/[userId]/posts/[postId]/get.ts
export default async (req, res) => {
const { userId, postId } = req.params;
const post = await db.posts.findFirst({
where: {
id: parseInt(postId),
userId: parseInt(userId),
},
});
res.json({ post });
};Optional Parameters
// controllers/search/[[query]]/get.ts
export default async (req, res) => {
const { query } = req.params;
if (query) {
const results = await searchDatabase(query);
res.json({ query, results });
} else {
res.json({ message: 'Search endpoint - add query param' });
}
};Framework Support
Route-wizard supports multiple frameworks:
// Express
import express from 'express';
import { registerRoutes } from '@chaeco/route-wizard';
const app = express();
registerRoutes(app, { dir: './controllers' });
// Koa
import Koa from 'koa';
import { registerRoutes } from '@chaeco/route-wizard';
const app = new Koa();
registerRoutes(app, { dir: './controllers' });
// Fastify
import fastify from 'fastify';
import { registerRoutes } from '@chaeco/route-wizard';
const app = fastify();
registerRoutes(app, { dir: './controllers' });📚 API Reference
registerRoutes(app, options)
Register routes to your application.
Parameters
app: Framework app instance (Express, Koa, Fastify, etc.)options: Configuration options
Options
dir(string): Path to controllers directory (default:'./controllers')prefix(string): Route prefix (default:'')logEnabled(boolean): Enable logging (default:true)separator(string): Separator for filename-based routing (default:'.')maxDepth(number): Maximum depth for nested routes (optional)performanceMonitor(PerformanceMonitor): Optional performance monitor instance
Example
registerRoutes(app, {
dir: './routes',
prefix: '/api',
logEnabled: false,
});createRouteWizard(options)
Create a route wizard with optional performance monitoring.
Parameters
options: Configuration options
Options
dir(string): Path to controllers directoryprefix(string): Route prefix (optional)logEnabled(boolean): Enable logging (default:true)separator(string): Separator for filename-based routing (default:'.')maxDepth(number): Maximum depth for nested routes (optional)enableMonitoring(boolean): Enable performance monitoring (default:false)
Returns
Object with the following methods:
register(app): Register routes to the appgetMetrics(): Get performance metricsgetSummary(): Get formatted metrics summary
Example
const wizard = createRouteWizard({
dir: './controllers',
enableMonitoring: true,
});
wizard.register(app);
console.log(wizard.getMetrics());
console.log(wizard.getSummary());PerformanceMonitor
Monitor performance metrics for route operations.
Methods
recordRouteScan(duration: number): Record route scan durationrecordRequest(responseTime: number): Record request response timerecordCacheHit(): Record cache hitrecordCacheMiss(): Record cache missgetMetrics(): Get current metricsgetMetricsSummary(): Get formatted summaryreset(): Reset all metrics
Metrics Properties
routeScanTime(number): Average route scan time in millisecondscacheHitRate(number): Cache hit rate (0-1)totalRequests(number): Total number of requestsaverageResponseTime(number): Average response time in millisecondsmemoryUsage: Node.js memory usage informationuptime(number): Monitor uptime in milliseconds
Example
const monitor = new PerformanceMonitor();
monitor.recordRouteScan(50);
monitor.recordRequest(100);
monitor.recordCacheHit();
const metrics = monitor.getMetrics();
console.log(metrics.routeScanTime);
console.log(monitor.getMetricsSummary());scanRoutes(dir, options?)
Scan and return all routes from a directory.
Parameters
dir(string): Path to controllers directoryoptions(ScanOptions): Scan options
Options
separator(string): Separator for filename-based routing (default:'.')maxDepth(number): Maximum depth for nested routes (optional)
Returns
Array of Route objects with:
method(string): HTTP method (GET, POST, etc.)path(string): Route pathhandler(function): Route handlermiddlewares(function[]): Optional middleware array
Example
import { scanRoutes } from '@chaeco/route-wizard';
const routes = scanRoutes('./controllers');
routes.forEach(route => {
console.log(`${route.method} ${route.path}`);
});📄 License
MIT © chaeco
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
Development Setup
# Clone the repository
git clone https://github.com/chaeco/route-wizard.git
cd route-wizard
# Install dependencies
npm install
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Build the project
npm run build
# Run linting
npm run lint