使用@route裝飾器簡(jiǎn)化koa-router寫法

前言

本文所有代碼見github

koa-router

koa-routerkoa項(xiàng)目中被廣泛使用到的一個(gè)路由中間件。
koa-router的基本使用方法如下:

var Koa = require('koa');
var Router = require('koa-router');
 
var app = new Koa();
var router = new Router();
 
router.get('/', (ctx, next) => {
  // ctx.router available
});
// 在app中使用routes中間件
app
  .use(router.routes())
  .use(router.allowedMethods());

可以看到,如果項(xiàng)目中有很多路由,那么我們需要寫很多的類似router.get('xxx', () => {})這樣的代碼,重復(fù)勞動(dòng)(多寫了幾個(gè)單詞?)。我們需要一種方式來簡(jiǎn)化router的書寫,decorator(裝飾器/注解)登場(chǎng)了。

@RequestMapping

熟悉java spring開發(fā)的同學(xué)一定對(duì)@RequestMapping, @Controller這些注解不陌生。
比如用戶登錄接口/user/login, 對(duì)應(yīng)java spring路由寫法如下:

@RequestMapping(path = "/user")
public class UserController {
    @RequestMapping(path = "/login", method={RequestMethod.POST})
    public String login() {
        return "success";
    }
}

在javascript里也可以使用類似的寫法,接下來我用裝飾器來描述路由。

書寫Controller

假如我們的Controller文件如下, 我們一步一步實(shí)現(xiàn)這樣的寫法,訪問 api/monitor/alive
monitor.ts

import { route } from '@server/decorator/router';
@route('/api/monitor')
export default class {
  @route('/alive')
  monitor() {
    return {
      data: true,
      message: '成功'
    };
  }
}

實(shí)現(xiàn)@route裝飾器

可以看出@route裝飾器既能裝飾Class,也能裝飾成員方法;當(dāng)裝飾Class的時(shí)候,僅僅相當(dāng)于給路由添加前綴;裝飾成員方法的時(shí)候,即路由需要執(zhí)行對(duì)應(yīng)的方法。并返回Response到瀏覽器。
route.ts 代碼如下:

import { Context } from 'koa';
import * as assert from 'assert';
import * as Router from 'koa-router';

type Middleware = Router.IMiddleware;

export enum RequestMethod {
  GET = 'get',
  POST = 'post',
  DELETE = 'delete',
  ALL = 'all',
  PUT = 'put',
  HEAD = 'head',
  PATCH = 'patch',
}

// tslint:disable-next-line:no-any
const methodList = Object.keys(RequestMethod).map((k: any) => RequestMethod[k]);

type Method = 'get' | 'post' | 'put' | 'delete' | 'all' | 'head' | 'patch';

const rootRouter = new Router();

export function route(url: string | string[],
                      method?: Method,
                      // tslint:disable-next-line:no-any
                      middlewares: Middleware[] | Middleware = []): any {
  // tslint:disable-next-line:no-any
  return (target: any, name: string, descriptor?: any) => {

    const midws = Array.isArray(middlewares) ? middlewares : [middlewares];

    /**
     * 裝飾類
     */
    if (typeof target === 'function' && name === undefined  && descriptor === undefined) {
      assert(!method, '@route 裝飾Class時(shí),不能有method 參數(shù)' );

      /**
       * 我們將router綁定在 原型上,方便訪問
       */
      if (!target.prototype.router) {
        target.prototype.router = new Router();
      }
      /**
       * 僅僅設(shè)置Controller 前綴
       */
      target.prototype.router.prefix(url);

      /**
       * 使得當(dāng)前Controller 可以執(zhí)行一些公共的中間件
       */
      if (middlewares.length > 0) {
        target.prototype.router.use(...midws);
      }
      return;
    }

    /**
     * 裝飾方法
     */
    if (!target.router) {
      target.router = new Router();
    }

    if (!method) {
      method = 'get';
    }

    assert(!!target.router[method], `第二個(gè)參數(shù)只能是如下值之一 ${methodList}`);
    assert(typeof target[name] === 'function', `@route 只能裝飾Class 或者 方法`);

    /**
     * 使用router
     */
    target.router[method](url, ...midws, async (ctx: Context, next: Function) => {
      /**
       * 執(zhí)行原型方法
       */
      const result = await descriptor.value(ctx, next);
      ctx.body = ctx.body || result;
    });

    /**
     * 將所有被裝飾的路由掛載到rootRouter,為了暴露出去給 koa 使用
     */
    rootRouter.use(target.router.routes());
  };
}

/**
 * 暴露router給koa使用
 */
export function getRouter() {
  return rootRouter;
}

加載Controller

import { getRouter } from '@server/decorator/router';
import './hello';
import './monitor';

export default getRouter().routes();

本文一些思路借鑒于這里

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容