UNPKG

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
# 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 ``` [![npm version](https://badge.fury.io/js/yml-mvc-router.svg)](https://badge.fury.io/js/yml-mvc-router) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Node.js CI](https://github.com/Pinkuagrawal28/yml-mvc-router/workflows/CI/badge.svg)](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)**