routedeck v0.0.2
routedeck
Highly productive Class and Method Decorators for TypeScript and Express. Among other features, turns async Express router methods into exception safe Express routes.
It's all about productivity; with a 60-second learning curve.
Install
npm i --save routedeck
Basic Usage
@get('/')
async home(req: Request, res: Response, next: NextFunction) {
res.json({ message: 'OK' });
}
Middleware:
@get('/', middleware, moreMiddleware, evenMoreMiddleware)
async home(req: Request, res: Response, next: NextFunction) {
res.json({ message: 'OK' });
}
You have access to the following
Decorators:
@get
, @post
, @put
, @del
, @patch
, @all
, @head
, @options
, @controller
The request methods are self-explanatory with the exception of del, use @del
for delete
. Beyond sending in middleware, you can also send in custom errors message. See Error Handling below.
Methods:
RouteDeck
RouteDeck - The Router You Seek
The RouteDeck
method is vital. RouteDeck returns a normal express Router but built from your decorated methods. You can call this method during member declaration or in the constructor.
A Complete Router Class Example
// default-controller.ts
import { NextFunction, Request, Response, Router } from 'express';
import { get, RouteDeck } from 'routedeck';
class DefaultController {
// IMPORTANT: Builds your router out of the decorated routes.
router: Router = RouteDeck(this);
@get('/')
async home(req: Request, res: Response, next: NextFunction) {
res.json({ message: 'Welcome' });
}
}
// Create an instance of the class
// and export the router from that class.
export const defaultController = new DefaultController().router;
@controller
@controller
prepends a list of middleware to each route in the class. While each route can have middleware, you can use @controller
to add middleware to all routes in the class.
A Class using the @controller
.
// default-controller.ts
import { NextFunction, Request, Response, Router } from 'express';
import { get, RouteDeck, controller } from 'routedeck';
// pass in a two middleware functions
@controller(myAuthorizeMiddleware('admin'), myLogger)
class AdminController {
// IMPORTANT: Builds your router out of the decorated routes.
router: Router = RouteDeck(this);
@get('/' someMiddleware)
async adminHome(req: Request, res: Response, next: NextFunction) {
res.json({ message: 'Welcome Admin' });
}
}
// Create an instance of the class and export the router
export const adminController = new AdminController().router;
In the above class, the middleware will run as follows for the /
route:
myAuthorizeMiddleware('admin') // From the controller
myLogger // From the controller
someMiddleware // From the route
Every route in the class would have the myAuthorizeMiddleware
and myLogger
middleware added to it.
How to use the resulting router classes
Taking the prior into consideration; in your main app.ts
file:
import { defaultController } from './controllers/default';
import { adminController } from './controllers/admin';
// Setup
// etc...
// etc...
app.use('/', defaultController);
app.use('/backend', adminController);
Error Handling
Default Error Handling
Handle errors like your normally would in express. If your route has an exception it will call next()
and pass in the error thereby meeting the error route method signature. For those who are not aware of this technique, I provide an example below. Just make exception handling your last rout(s) in your server.
import { defaultController } from './controllers/default';
import { adminController } from './controllers/admin';
// Setup
// etc...
// etc...
app.use('/', defaultController);
app.use('/backend', adminController);
// 500 Logger - First Error Signature
app.use((err: any, req: Request, res: Response, next: NextFunction) => {
console.error(err.stack);
next(err); // next and pass the error again
});
// 500 Response - Second / next Error Signature
app.use((err: any, req: Request, res: Response, next: NextFunction) => {
res.status(500).json({ message: '500 Server Error' });
});
// listen ...
Note: Before moving forward it is import to note that you should always have error handing routes in your server.
Custom Error Handling
With each method decorator, you can pass in a custom error as either a string
or an object
as one of the parameters. Parameter order does not matter; parameters that are functions
are assumed middleware, and a parameter that is a string
or an object
is assumed a custom error.
Note: This may appear to be a rather verbose check using typeof
―it is. However, the middleware and custom error message checks are done once per decorated route at application startup, not with each route access.
All are valid:
@get('/' 'Customer Error Message');
@get('/' middleware1, middleware2, 'Customer Error Message');
@get('/' middleware1, 'Customer Error Message', middleware2);
@get('/' 'Customer Error Message', middleware1);
In all cases above, the following is produced if an exception is encountered:
{
"success": false,
"error": true,
"message": "Customer Error Message"
}
You can use an object.
@get('/' {myError: 'Error', code:1234});
@get('/' middleware1, middleware2, {myError: 'Error', code:1234});
@get('/' middleware1, {myError: 'Error', code:1234}, middleware2);
@get('/' {myError: 'Error', code:1234}, middleware1);
The object will be the response.
{
"myError": "Error",
"code": 1234
}
It all cases a 500 status code is produced.
Note: If you accidentally provide more than one custom error (string
| object
), routedeck will not throw an error. The last custom error found in the parameter list will be used.
So you are an expert in 60 seconds
- Decorate your async methods to turn them into routes
- You can use middleware and customer errors in your routes.
- Add a
@controller
to the class if you want to add middleware to all routes in the router for said class. - Make sure you call
RouteDeck(this)
in your class to build and return a router. - Export that router and use it like any other router, it is in fact just an express router.
I want more speed. I don't want to learn a new framework to get it.
Use routedeck!