yml-mvc-router
v0.1.0
Published
A configurable, Express-compatible routing module that maps routes from YAML to controllers following the MVC pattern
Maintainers
Readme
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
npm install yml-mvc-router🏁 Quick Start
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
/:
controller: HomeController.index
method: GET
/users/:id:
controller: UserController.show
method: GETcontrollers/HomeController.js
exports.index = async ({ view }) => {
return view('home', { title: 'Welcome!' });
};controllers/UserController.js
exports.show = async ({ params }) => {
return { userId: params.id }; // Returns JSON
};📋 Configuration Options
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
# 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
/admin:
prefix: /admin
middlewares:
- auth
- adminOnly
children:
/dashboard:
controller: AdminController.dashboard
method: GET
/users:
controller: AdminController.users
method: GETMiddleware with Options
/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:
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:
// 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:
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
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
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
/dashboard:
controller: DashboardController.index
assets:
css:
- css/dashboard.css
- https://cdn.example.com/charts.css
js:
- js/dashboard.jsTemplate (EJS)
<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:
git clone <repository>
cd yml-mvc-router
npm install
npm run exampleThen visit:
http://localhost:3000- Home pagehttp://localhost:3000/about- About pagehttp://localhost:3000/api/status- JSON APIhttp://localhost:3000/users/1- User profile with middlewarehttp://localhost:3000/admin/dashboard- Admin area (route groups)http://localhost:3000/routes- Route inspector
Run tests:
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:
// 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
🤝 Contributing
Contributions, issues and feature requests are welcome! See CONTRIBUTING.md for details.
Development Setup
# 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 actionBuilt with ❤️ for the Express.js community by Pinku Agrawal
