API for route decorators
ES7 decorators that simplify route creation. Using these decorators, you can write your controllers like below and have all the routes populated. This is just an API which provides you the needed route objects, which you can use for your own router. Totally framework independent.
Usage
-
Install reflect-metadata package:
npm install reflect-metadata --save
and import it somewhere in the global place of your app before any decorator usage or import (for example in
app.ts
):import "reflect-metadata";
-
You may need to install node typings:
npm install @types/node --save
-
Enabled following settings in
tsconfig.json
:
"emitDecoratorMetadata": true,"experimentalDecorators": true,
Route Decorators
Koa
@ @ async {} @ async {}
Express
@ @ async {} @ async {}
Once the decorators are applied, every controller instance will receive a $routes
array, which you can use to define actual Koa/Express routes.
Assume the above UserCtrl
definition, you can define routes in UserCtrl
's constructor (although really you can put the code anywhere) as follows:
Koa
; // Inside controller constructorthisrouter = for const method url middleware fnName of this$routes thisroutermethodurl ...middleware thisfnName
Express
// Inside controller constructorthisrouter = expressfor const method url middleware fnName of this$routes thisroutermethodurl ...middleware { thisfnNamereq res next }
You can move the above logic to some base controller in your app and reuse it for every controller. For example:
{ thisrouter = for const method url middleware fnName of this$routes thisroutermethodurl ...middleware thisfnName; } @ // decorated methods as above
Route Parameter Decorators
Example:
@ async //do something
to make use of the decorators you have to do 2 things:
- Register a transformer Function which fits your needs (Framework specific)
Express
; { return { return reqparamsparam; }}DecoratorProcessor;
Koa
{ return { return ctxrequestparam; }}DecoratorProcessor;
Transformer functions are returning a function which has the function definition of your route functions
Every Decorator has a appropriate Decoratortype, see all types: DecoratorTypes
- Apply the decorators
; { DecoratorProcessor; }
Recommened use in same base controller for routes
{ DecoratorProcessor; thisrouter = for const method url middleware fnName of this$routes thisroutermethodurl ...middleware thisfnName; }
Can also be used without route parameters:
{ DecoratorProcessor; } { return { console; //1 console; //2 console; //3 console; //abc return "test"+req+res+next+"test"+param; }} DecoratorProcessor; : void console; //test123testabc let testReq = 1;let testRes = 2;let testNext = 3;;
Custom Route Parameter Decorators
; // register the decorator with unique string valueconst customDecoratorIdentifier="EveryDecoratorHasItsOwnIdentifierString"; //first define your decorator function { // define your own parameters // call the static setDecorator function with given values and your identifier // the last parameter is an array from your parameter values return { ; };} // define processor function{ return { return value+"4"; }} // set function for decorator with unique decorator identifierDecoratorProcessor; // use it { DecoratorProcessor; } async : void console; //some1234
Recommened usage with Typescript
As the decorators can also be used without a framework (for whatever use case you may have) here are tips for typescript usage.
- Type safety in the processor function:
;; const customDecoratorIdentifier="EveryDecoratorHasItsOwnIdentifierString"; { return { ; };} { return { ifparam instanceof SomeVeryComplicatedObject === false throw "You need to call the function with the right type"; // we can be sure now that param is SomeVeryComplicatedObject return param; // return ReturnObject type }} DecoratorProcessor;
- Type safety in the consuming function:
Define the parameter as union type, so it can be called type safe with the calling parameter object and also be consumed as the type which the processor function returns (in this case the ReturnObject).
Optionally you can use instanceof to check the type at runtime.
{ DecoratorProcessor; } : void result = result as ReturnObject; console; // work with ReturnObject type return result; let myObject: SomeVeryComplicatedObject = ; ;
Additional Notes
when you use route parameter decorators all other non decorated parameters will be undefined
@ async console; console; // undefined console;
No decorator has built-in error handling, it's all up to you.
Decorators
Class
@Controller(path: optional, ...middleware: optional)
Method
@Route(method, path: optional, ...middleware: optional)
@Head
,@Options
,@Get
,@Post
,@Put
,@Patch
,@Del
,@Delete
,@All
: wrappers of@Route
that automatically supply themethod
argument.
Method parameters
@RequestParam(paramName, ...validators: optional)
@QueryParam(paramName, ...validators: optional)
@Request()
@Response()
@Body()
@Next()
- And every Decorator you can think of ;-)
- .. more coming, feel free to suggest/pr
Test
npm installnpm test