yml-mvc-router
Version:
A configurable, Express-compatible routing module that maps routes from YAML to controllers following the MVC pattern
413 lines (330 loc) โข 10 kB
Markdown
# yml-mvc-router
A configurable, Express-compatible routing module that maps routes from YAML to controllers following the MVC pattern. Make your Express apps declarative, predictable, and easier to maintain.
## ๐ Features
- **YAML Route Configuration** - Define routes declaratively in `routes.yml`
- **Automatic Controller Resolution** - Smart loading from your controllers directory
- **Smart Response Detection** - Controller return values decide JSON vs view rendering
- **Asset Injection** - Per-route CSS/JS assets automatically injected into templates
- **Hot Reload** - Development mode automatically reloads routes on file changes
- **Route Inspector** - Visual debugging tool at `/routes`
- **Middleware Support** - Easy middleware configuration and chaining
- **Route Groups** - Organize routes with shared prefixes and middleware
- **EJS Ready** - Works out-of-the-box with EJS (extensible for other view engines)
## ๐ฆ Installation
```bash
npm install yml-mvc-router
```
[](https://badge.fury.io/js/yml-mvc-router)
[](https://opensource.org/licenses/MIT)
[](https://github.com/Pinkuagrawal28/yml-mvc-router/actions)
## ๐ Quick Start
```javascript
const express = require('express');
const ymlRouter = require('yml-mvc-router');
const app = express();
// Basic setup
app.use(ymlRouter({
routes: './routes/routes.yml',
controllers: './controllers'
}));
app.listen(3000);
```
**routes/routes.yml**
```yaml
/:
controller: HomeController.index
method: GET
/users/:id:
controller: UserController.show
method: GET
```
**controllers/HomeController.js**
```javascript
exports.index = async ({ view }) => {
return view('home', { title: 'Welcome!' });
};
```
**controllers/UserController.js**
```javascript
exports.show = async ({ params }) => {
return { userId: params.id }; // Returns JSON
};
```
## ๐ Configuration Options
```javascript
app.use(ymlRouter({
routes: './routes/routes.yml', // Path to routes file
controllers: './controllers', // Controllers directory
middlewares: './middlewares', // Middlewares directory
views: './views', // Views directory
assets: './public', // Static assets directory
engine: 'ejs', // View engine name
watch: true, // Enable hot reload (dev)
devInspector: true, // Enable /routes inspector
controllerExt: ['.js'], // Controller file extensions
resolveController: null, // Custom controller resolver
plugins: [] // Plugin array (future)
}));
```
## ๐บ๏ธ routes.yml Schema
### Basic Routes
```yaml
# Simple route
/:
controller: HomeController.index
method: GET
# With middleware and assets
/users/:id:
controller: UserController.show
method: GET
middlewares:
- auth
- rateLimiter
assets:
css:
- css/user.css
js:
- js/user.js
# Force response type
/api/data:
controller: ApiController.getData
method: GET
response: json # or 'view'
```
### Route Groups
```yaml
/admin:
prefix: /admin
middlewares:
- auth
- adminOnly
children:
/dashboard:
controller: AdminController.dashboard
method: GET
/users:
controller: AdminController.users
method: GET
```
### Middleware with Options
```yaml
/api/posts:
controller: PostController.create
method: POST
middlewares:
- auth
- { name: rateLimiter, options: { max: 5, windowMs: 60000 } }
```
## ๐ฎ Controller Contract
Controllers are plain Node.js modules that export functions. Each action receives a context object:
```javascript
exports.actionName = async (context) => {
// Context contains:
const {
req, res, next, // Express objects
params, query, body, // Request data
view, // View helper function
route, // Route metadata
services // DI container (future)
} = context;
// Return options:
return view('template', data); // Render view
return { view: 'template', data }; // Explicit view
return { someData: 'value' }; // JSON response
return null; // Call next()
// Or manipulate res directly
res.json({ custom: 'response' });
};
```
### Response Types
**View Rendering:**
```javascript
// Using view helper (recommended)
exports.show = async ({ view, params }) => {
const user = await getUserById(params.id);
return view('user/profile', { user });
};
// Explicit view object
exports.show = async ({ params }) => {
const user = await getUserById(params.id);
return {
view: 'user/profile',
data: { user }
};
};
```
**JSON Response:**
```javascript
exports.apiEndpoint = async ({ body }) => {
const result = await processData(body);
return { success: true, result }; // Auto JSON
};
```
## ๐ง Middleware
Create middleware files in your `middlewares` directory:
**middlewares/auth.js**
```javascript
module.exports = (options = {}) => {
return (req, res, next) => {
// Your auth logic
if (!req.headers.authorization) {
return res.status(401).json({ error: 'Unauthorized' });
}
req.user = decodeToken(req.headers.authorization);
next();
};
};
```
**middlewares/rateLimiter.js**
```javascript
module.exports = ({ max = 10, windowMs = 60000 } = {}) => {
return (req, res, next) => {
// Rate limiting logic
next();
};
};
```
## ๐จ Asset Management
Assets defined in routes are automatically injected into `res.locals.assets`:
**routes.yml**
```yaml
/dashboard:
controller: DashboardController.index
assets:
css:
- css/dashboard.css
- https://cdn.example.com/charts.css
js:
- js/dashboard.js
```
**Template (EJS)**
```html
<head>
<!-- Route-specific CSS -->
<% if (assets && assets.css) { %>
<% assets.css.forEach(css => { %>
<link rel="stylesheet" href="<%= css %>">
<% }); %>
<% } %>
</head>
<body>
<!-- Your content -->
<!-- Route-specific JS -->
<% if (assets && assets.js) { %>
<% assets.js.forEach(js => { %>
<script src="<%= js %>"></script>
<% }); %>
<% } %>
</body>
```
## ๐ฅ Hot Reload & Development
### Automatic Reloading
In development mode (`NODE_ENV !== 'production'` or `watch: true`), yml-mvc-router automatically watches your `routes.yml` file and reloads routes when changed.
### Route Inspector
Visit `/routes` in your browser to see:
- All registered routes
- Controller mappings
- Middleware chains
- Asset configurations
- Registration status and errors
The inspector auto-refreshes every 5 seconds and is only available in development mode.
## ๐งช Testing
Run the example application:
```bash
git clone <repository>
cd yml-mvc-router
npm install
npm run example
```
Then visit:
- `http://localhost:3000` - Home page
- `http://localhost:3000/about` - About page
- `http://localhost:3000/api/status` - JSON API
- `http://localhost:3000/users/1` - User profile with middleware
- `http://localhost:3000/admin/dashboard` - Admin area (route groups)
- `http://localhost:3000/routes` - Route inspector
Run tests:
```bash
npm test
npm run test:watch
```
## ๐ Example Project Structure
```
my-app/
โโโ app.js
โโโ routes/
โ โโโ routes.yml
โโโ controllers/
โ โโโ HomeController.js
โ โโโ UserController.js
โ โโโ ApiController.js
โโโ middlewares/
โ โโโ auth.js
โ โโโ rateLimiter.js
โโโ views/
โ โโโ layout.ejs
โ โโโ home.ejs
โ โโโ user.ejs
โโโ public/
โโโ css/
โโโ js/
```
## ๐จ Error Handling
yml-mvc-router forwards all controller errors to Express error handlers:
```javascript
// Controller throws error
exports.problematic = async () => {
throw new Error('Something went wrong');
};
// Express error handler catches it
app.use((err, req, res, next) => {
console.error('Controller error:', err.message);
res.status(500).json({
error: 'Internal server error',
message: err.message
});
});
```
## ๐ Security Considerations
- Controllers and middleware are resolved only from configured directories
- Route inspector is disabled in production by default
- No code execution from YAML content
- Standard Express security best practices apply
## ๐ฃ๏ธ Roadmap
### v0.2 (Next)
- [ ] Plugin system for extensibility
- [ ] View adapter for Pug, Handlebars, React SSR
- [ ] CLI tools (`yml-router:list`, `yml-router:validate`)
- [ ] Advanced middleware configuration
### v1.0 (Future)
- [ ] TypeScript definitions
- [ ] Asset bundling and optimization
- [ ] Route caching for production
- [ ] Performance metrics and monitoring
- [ ] Advanced debugging tools
## ๐ค Contributing
Contributions are welcome! Please read our contributing guidelines and submit pull requests for any improvements.
## ๐ License
MIT License - see LICENSE file for details.
## ๐ Support
- ๐ [Documentation](https://github.com/Pinkuagrawal28/yml-mvc-router)
- ๐ [Issue Tracker](https://github.com/Pinkuagrawal28/yml-mvc-router/issues)
- ๐ฌ [Discussions](https://github.com/Pinkuagrawal28/yml-mvc-router/discussions)
- ๐ง [Email](mailto:pinkuagrawal28@gmail.com)
## ๐ค Contributing
Contributions, issues and feature requests are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
### Development Setup
```bash
# Clone the repository
git clone https://github.com/Pinkuagrawal28/yml-mvc-router.git
cd yml-mvc-router
# Install dependencies
npm install
# Run tests
npm test
# Run example app
npm run example
# Visit http://localhost:3000 to see it in action
```
---
**Built with โค๏ธ for the Express.js community by [Pinku Agrawal](https://github.com/Pinkuagrawal28)**