Define ExpressJS routes as Typescript classes using decorators. Inspired by the MVC pattern.
npm install eec --save
This package makes use of decorators and reflect-metadata. so you will also need to enable the following flags in your tsconfig.json
:
"experimentalDecorators": true
"emitDecoratorMetadata": true
Here's a basic example to get started. Note that buildController(...)
returns a valid Express Router instance that can be used directly with app.use(...)
.
import express from 'express';
import { route, get, post, buildController, BaseController } from 'eec';
class DashboardController extends BaseController {
static PATH = '/dashboard'
@route({ index: true }) // Responds to: /dashboard. `index` says to use as index route
async index() {
this.response.status(200).send(`Welcome to the dashboard!`);
}
@get() // Responds to /dashboard/users
async users() {
// Also req.params & req.query
if(this.params.someParameter || this.query.anotherParameter) {
this.response.json({ name: 'John' });
return;
}
this.response.sendStatus(404)
}
@post(':id') // Responds to /dashboard/updateUser/<user_id>
async updateUser() {
if(this.params.id === 'admin') {
this.response.sendStatus(403);
}
else {
this.response.status(200).send('Success!');
}
}
}
const app = express();
app.use(buildController(DashboardController))
// Go to http://localhost:3000/dashboard/
app.listen(3000, () => { console.log("App listening!") })
The @route()
decorator supports many more configurations. Take a look at the src/examples
directory to get started with more scenarios.
To run all the examples provided:
- Clone this repo
npm install
npm start
A server will be listening at port 3000!
npm install
npm test
class DashboardController {
static PATH = '/dashboard'
// Responds to: /dashboard/users. The function name is taken to be the endpoint!
@route()
async users(req, res) {
await this.doSomeStuff();
res.json({ name: 'John', age: 34 })
}
// All method NOT marked as @route() are ignored, but are still avilable in each route.
async doSomeStuff() { console.log('Working!') }
}
// Don't want a GET route? Specify a different one!
@route({ type: 'post' })
async updateUsers(req, res) { ... }
// Or use one of the several aliases
@post()
async updateUsers(req, res) { ... }
// Respond to multiple HTTP methods
@route({ type: ['post', 'put', 'delete'] })
async updateRecords(req, res) { ... }
@route({ middleware: [Logger, Authentication] })
async updateData(req, res) { ... }
@useMiddleware(Logger) //Pass in array for multiple
class DashboardController {
static PATH = '/dashboard'
// This middleware will run AFTER the Logger!
@route({ middleware: Authentication })
async users(req, res) { ... }
}
export default buildController(DashboardController)
class DashboardController {
static PATH = '/dashboard'
@get()
async users() {
let raw = this.query.myNum
let num = Number.parseInt(raw)
this.response.json({ result: num })
/** There are aliases provided for:
*
* req --> this.request
* res --> this.response
* next --> this.next,
*
* res.locals --> this.locals
* req.params --> this.params
* req.query --> this.query
*
* These can be used in any number of
* helper functions within the class!
*/
}
}
export default buildController(DashboardController)