本文首發於:用Decorator掌握Koa路由
在Spring中Controller長如許
@Controller
public class HelloController{
@RequestMapping("/hello")
String hello() {
return "Hello World";
}
}
另有Python上的Flask框架
@app.route("/hello")
def hello():
return "Hello World"
二者都用decorator來掌握路由,如許寫的優點是更簡約、更文雅、更清楚。
反觀Express或Koa上的路由
router.get('/hello', async ctx => {
ctx.body = 'Hello World'
})
完整差了一個層次
JS從ES6最先就有Decorator
了,只是瀏覽器和Node都還沒有支撐。須要用babel-plugin-transform-decorators-legacy
轉義。
Decorator基礎原理
起首須要明白兩個觀點:
- Decorator只能作用於類或類的要領上
- 假如一個類和類的要領都是用了Decorator,類要領的Decorator優先於類的Decorator實行
Decorator基礎原理:
@Controller
class Hello{
}
// 等同於
Controller(Hello)
Controller是個一般函數,target
為潤飾的類或要領
// Decorator不傳參
function Controller(target) {
}
// Decorator傳參
function Controller(params) {
return function (target) {
}
}
假如Decorator是傳參的,縱然params有默認值,在調用時必需帶上括號,即:
@Controller()
class Hello{
}
如安在Koa中運用Decorator
我們可以對koa-router
中間件舉行包裝
先回憶一下koa-router
基礎運用要領:
var Koa = require('koa');
var Router = require('koa-router');
var app = new Koa();
var router = new Router();
router.get('/', async (ctx, next) => {
// ctx.router available
});
app
.use(router.routes())
.use(router.allowedMethods());
再設想一下最終目標
@Controller({prefix: '/hello'})
class HelloController{
@Request({url: '/', method: RequestMethod.GET})
async hello(ctx) {
ctx.body = 'Hello World'
}
}
類內部要領的裝潢器是優先實行的,我們須要對要領從新定義
function Request({url, method}) {
return function (target, name, descriptor) {
let fn = descriptor.value
descriptor.value = (router) => {
router[method](url, async(ctx, next) => {
await fn(ctx, next)
})
}
}
}
對RequestMethod舉行花樣一致
const RequestMethod = {
GET: 'get',
POST: 'post',
PUT: 'put',
DELETE: 'delete'
}
Controller裝潢器需將Request要領添加到Router實例並返回Router實例
import KoaRouter from 'koa-router'
function Controller({prefix}) {
let router = new KoaRouter()
if (prefix) {
router.prefix(prefix)
}
return function (target) {
let reqList = Object.getOwnPropertyDescriptors(target.prototype)
for (let v in reqList) {
// 消除類的組織要領
if (v !== 'constructor') {
let fn = reqList[v].value
fn(router)
}
}
return router
}
}
至此,裝潢器基礎功能就完成了,基礎運用要領為:
import {Controller, Request, RequestMethod} from './decorator'
@Controller({prefix: '/hello'})
export default class HelloController{
@Request({url: '/', method: RequestMethod.GET})
async hello(ctx) {
ctx.body = 'Hello World'
}
}
在App實例中同路由一樣use即可。