路由和控制器
midway 使用 koa-router 作为路由的承载者,同时在 ts 的语法上做了一些简化,我们将路由和控制器放在了一起,使用装饰器来标注路由。
由于 midway 采用了 IoC 自扫描机制,使得在一定程度上弱化了目录结构约定,通过装饰器的机制,可以非常方便的进行解耦,按业务逻辑拆分等。
现在可以在任意目录下创建 controller,不再限定 app/controller 目录,同理, 其他装饰器也不限定。
现在可以做到比如 src/web/controller
下放 controller,也可以按业务维度分,比如 user
目录,包含跟用户相关所有的 controller/service/dao 等,对微服务或者 serverless 比较友好。
路由装饰器
在新的 ts 体系中,我们的控制器目录为 app/controller
,我们在其中编写 *.ts
文件。例如下面的 userController.ts
,我们提供了一个获取用户的接口。
import { provide, controller, inject, get } from 'midway';
@provide()
@controller('/user')
export class UserController {
@inject('userService')
service: IUserService;
@inject()
ctx;
@get('/:id')
async getUser(): Promise<void> {
const id: number = this.ctx.params.id;
const user: IUserResult = await this.service.getUser({ id });
this.ctx.body = { success: true, message: 'OK', data: user };
}
}
我们创建了 @controller
装饰器用来定义这个类为 Controller,同时 ,提供了方法装饰器用于标注请求的类型。
便于大家理解,@controller
的参数为字符串 pattern,我们会将这个值传入 router.prefix(prefix)
的参数中。
midway 针对 web 请求,提供了和 koa-router 对应的方法装饰器,列表如下。
这几个装饰器用于修饰不同的异步方法,同时对应到了 koa-router 的相应的方法。和原有提供的控制器一样,每个控制器都为异步方法,默认参数为 koa 上下文。
@get('/:id')
async getUser(ctx): Promise<void> {
// TODO ctx...
}
路由绑定
在以往框架的写法中,提供的 app/router
文件,虽然可以直接使用,但是由于控制器被 IoC 管控的关系,会有一些区别。
和以往的写法不同的是,我们需要从容器中拿到对应的 控制器实例,并绑定到路由的 pattern 上。
假如我们有一个控制器,同时没有提供 @controller
装饰器,表明他不是一个控制器,在应用初始化时不会自动绑定到某个路由上,但是由于有 @provide
装饰器,他会被 IoC 容器所加载。
// app/controller/api.ts
@provide()
export class BaseApi {
async index(ctx) {
ctx.body = 'index';
}
}
假如我们希望这个控制器可以被外部的路由使用。
// app/router.ts
module.exports = function (app) {
app.get('/api/index', app.generateController('baseApi.index'));
};
midway 扩展了一个 app.generateController
的方法来简化绑定的这个步骤,参数为 ClassName.methodName
的字符串形式。