koa+ts 通过自动导入路由文件,通过路由装饰器注册路由

koa 类装饰器 路由装饰器 自动注册路由文件

koa 中如何优雅地定义路由?

最近在搞 nest.js,学习装饰器想起,以前刚接触 koa/experss 时,就想着怎么能把路由写的优雅一点

不想写一堆的router.get('/', (ctx, next) => {});当时只是简单的把文件分开

直到用了nest.js,如果在 koa/express 中也实现路由装饰器,岂不是也很好,就在此简单记录一下,koa 中实现路由装饰器

准备工作

先准备一个极简的 ts+koa 的基础项目

  1. 新建 koa-adorner 文件夹

  2. 初始化项目

npm init
  1. 安装依赖
npm i typescript ts-node-dev tslint @types/node -D
npm i koa koa-router
  1. 配置 scripts 启动项目
"start": "ts-node-dev ./src/index.ts -P tsconfig.json --no-cache"
  1. tslang配置 tsconfig.json 以支持装饰器
{
  "compilerOptions": {
    "module": "commonjs",
    "noImplicitAny": false,
    "removeComments": true,
    "preserveConstEnums": true,
    "sourceMap": true,
    "moduleResolution": "node",
    "experimentalDecorators": true, // 使用装饰器
    "allowSyntheticDefaultImports": true,
    "target": "es2017",
    "lib": ["es2015"],
    "outDir": "./dist",
    "typeRoots": ["./node_modules/@types"]
  },
  "include": ["src/**/*"]
}

  1. 创建 src/index.ts ,搭建一个简单的 http 服务内容如下

此时启动项目,访问 3000 端口可以看到响应了 get

import * as Koa from "koa";
import * as Router from "koa-router";

const app = new Koa();
const router = new Router(); // 实例化路由

router.get("/", async (ctx: Koa.Context) => {
  ctx.body = "get";
});
router.post("/", async (ctx: Koa.Context) => {
  ctx.body = "post";
});
app.use(router.routes());
app.listen(3000, () => {
  console.log("The service starts at port 3000");
});

在实际项目中,router 是复杂的,可能在 n 多个文件,然后 n 多个 router.get

而我们现在就是要消灭掉并且实现多文件自动加载,优雅得书写我们的路由文件

实现一个自动注册所有路由文件的方法

/src/utils/decorator.ts

import * as glob from "glob";

// 路由在此实例化
const router = new KoaRouter();

// 自动注册 {folder} 文件下的所有路由
export const load = (folder: string, options: LoadOptions = {}): KoaRouter => {
  const extname = options.extname || ".{js,ts}";
  glob
    .sync(require("path").join(folder, `./**/*${extname}`))
    .forEach((item) => require(item));
  return router;
};

/src/index.ts

注释原有的 router,使用 load 导入 src/routes 下的路由文件

import * as Koa from "koa";
// import * as Router from "koa-router";
import { load } from "./utils/decorator";
import { resolve } from "path";

const app = new Koa();
// const router = new Router(); // 实例化路由

// router.get("/", async (ctx: Koa.Context) => {
//   ctx.body = "get";
// });
// router.post("/", async (ctx: Koa.Context) => {
//   ctx.body = "post";
// });

const router = load(resolve(__dirname, "./routes"), {
  // extname: "",
});
app.use(router.routes());
app.listen(3001, () => {
  console.log("The service starts at port 3000");
});

创建一个路由文件

/src/routes/test.ts

此时我们期望这样书写即可完成路由的注册

其中@Controller("test")类装饰器将作为路由的前缀,我们可以在此组织相关模块的代码

@get("list") 也就是说我们可以通过 get 请求访问/test/list

@post() 如果不传参数,就默认获取add作为路径,也就是说我们可以通过 post 请求访问/test/add

import * as Koa from "koa";
import { Controller, get, post } from "../utils/decorator";

@Controller("test")
export default class testController {
  @get("list")
  public async list(ctx: Koa.Context) {
    const data = [{ id: 1, name: "测试" }];
    ctx.body = { ok: 1, data };
  }
  @post()
  public async add(ctx: Koa.Context) {
    const data = [{ id: 1, name: "测试" }];
    ctx.body = { ok: 1, data };
  }
}

实现 Controller 装饰器以及路由方法类

/src/utils/decorator.ts

同样在 decorator 中,我们新增如下代码

import * as Koa from "koa";
import * as KoaRouter from "koa-router";

type LoadOptions = {
  extname?: string,
};

type RouteOptions = {
  prefix?: string,
  middlewares?: Array<Koa.Middleware>,
};

type HTTPMethod = "get" | "post";

// Controller类装饰器 作用:给controller类添加路由前缀,当然愿意的话也可以不使用Controller类装饰器
export const Controller = (path = "") => {
  // 给controller类添加路由前缀
  return function(target) {
    target.prefix = "/" + path;
  };
};

// 方法装饰器
const decorate = (
  method: HTTPMethod,
  path: string,
  options: RouteOptions = {},
  router: KoaRouter
) => {
  return (target, property: string, descriptor) => {
    process.nextTick(() => {
      const { prefix = "" } = target.constructor; //Controller前缀
      const roterPath = "/" + (path || property); //去参数路径或者方法名作为路径

      // 添加中间件数组
      const middlewares = [];
      if (options.middlewares) {
        middlewares.push(...options.middlewares);
      }
      if (target.middlewares) {
        middlewares.push(...target.middlewares);
      }
      middlewares.push(target[property]);
      //router rul
      const url = options.prefix
        ? prefix + options.prefix + roterPath
        : prefix + roterPath;

      router[method](url, ...middlewares);
    });
  };
};
// method多包一层
const method = (method: HTTPMethod) => (
  path?: string,
  options?: RouteOptions
) => decorate(method, path, options, router);

// 中间件 改天专门写一下
export const middlewares = (middlewares: Koa.Middleware[]) => {
  return function(target: { prototype: { middlewares: any[] } }) {
    target.prototype.middlewares = middlewares;
  };
};

// 最终导出get、post ,此处以这两个为例
export const get = method("get");
export const post = method("post");

至此,我们在 koa 中已经简单得实现了路由装饰器,通过Controller @get等装饰器语法减去了重复繁琐的工作

也有利于我们组织代码与维护,其中跟多请求方式的,Controller 甚至根据类名来构建,请求数据校验等,可以根据业务进行完善,有时间再分享下 koa 的内容

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个比较具体的问题,我尽量给出详细的回答。 首先,你需要了解每个工具的作用: - Node.js: 一个基于 Chrome V8 引擎的 JavaScript 运行时,可用于构建高性能的网络应用程序。 - Midway.js: 一个基于 Egg.js 的 Serverless Node.js 框架,提供了函数计算、API 网关等 Serverless 场景下的解决方案。 - Koa: 一个基于 Node.js 平台的 Web 开发框架,旨在提供更小、更富有表现力、更健壮的 Web 应用程序。 - TypeScript: 是 JavaScript 的一个超集,可以编译成纯 JavaScript。 接下来,你可以按照以下步骤进行开发: 1. 创建一个基于 Midway.js 的应用程序: ``` $ npm init midwayjs-app jsapi ``` 2. 安装需要的依赖: ``` $ cd jsapi $ npm install koa koa-bodyparser koa-router cross-env --save $ npm install @midwayjs/koa @midwayjs/faas @midwayjs/socketio --save $ npm install typescript ts-node @types/node --save-dev ``` 3. 创建 TypeScript 配置文件 `tsconfig.json`: ``` { "extends": "@midwayjs/tsconfig/tsconfig.json", "compilerOptions": { "outDir": "dist", "rootDir": "src" }, "include": ["src"] } ``` 4. 创建一个简单的 TypeScript 控制器: ``` import { Provide, Controller, Get, Post, Body } from '@midwayjs/decorator'; import { Context } from 'koa'; @Provide() @Controller('/api') export class ApiController { @Get('/hello') async hello(ctx: Context) { ctx.body = 'Hello Midwayjs'; } @Post('/share') async share(@Body() body) { const { url } = body; // 解析分享链接 // ... // 返回解析结果 return { title, desc }; } } ``` 5. 创建 Koa 应用程序: ``` import { App, Config, Inject } from '@midwayjs/decorator'; import { ILifeCycle, IMidwayApplication } from '@midwayjs/core'; import { Application } from 'egg'; import * as bodyParser from 'koa-bodyparser'; import * as Router from 'koa-router'; @Config() export class AppConfig implements ILifeCycle { @Inject() app: IMidwayApplication; async onReady() { const app = this.app.getApplication() as Application; // 添加中间件 app.use(bodyParser()); app.use(app.get('koaRouter').routes()); // 启动应用程序 app.listen(3000, () => { console.log('Server listening on http://localhost:3000'); }); } } @App() export class ApiApplication implements ILifeCycle { @Inject() app: IMidwayApplication; async onReady() { const router = this.app.getApplicationContext().get('koaRouter') as Router; router.get('/api/hello', async (ctx) => { ctx.body = 'Hello Koa'; }); } } ``` 6. 启动应用程序: ``` $ npm run dev ``` 7. 使用 curl 或者 Postman 等工具测试 API: ``` $ curl -X GET http://localhost:3000/api/hello ``` ``` $ curl -X POST http://localhost:3000/api/share -d '{"url": "http://example.com"}' ``` 这样,一个基于 Node.js、Midway.js、Koa、TypeScript 的 API 解析程序就完成了。当然,这只是一个简单的示例,你可以根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值