tegg
tegg copied to clipboard
[RFC] 增强Controller能力与相关HttpMethod
- 开始时间: 2021/12/16
- RFC PR:
- tegg Issue:
背景
参照: 提供更加简单化请求方法的修饰器的讨论
思路
所有Controller 类型会通过namespace进行区分
-
为了方便区分
Controller
,RestController
,HttpController
,RpcControlle
需要单独划分命名空间以方便归类。 将HttpController和简化后的Controller将会被划分到 http namespace, RestController 会被划分到rest namespace,RpcControlle
会被划分到 rpc namespace。 -
以下将通过
import
的形式具体描述:import {Controller, HttpController} from '@eggjs/tegg/http'; import {RestController} from '@eggjs/tegg/rest'; import {RpcController} from '@eggjs/tegg/rpc';
新增baseRoot
-
config新增baseRoot能力
tegg:{ baseRoot:string }
-
通过这个字段可以全局调整路由根路径
//config.default.ts tegg:{ baseRoot:'/tegg' } //controller/fruitController.ts @RestController('/api/v1') //or Controller('/api/v1') class Fruit { // GET /api/v1/ @List home() { } }
此时路径会被修正到‘/tegg/api/v1'’
新增Controller
-
所有的方法入参暂定为继承自HttpController:
Controller(path?: string, protoName?: string, controllerName?: string);
新增Controller下Http Method修饰器
-
新的
Http Method
会跟HTTPMethodEnum
的枚举保持一致,包含GET
,POST
,PUT
,DELETE
,PATCH
,OPTIONS
,HEAD
-
所有的方法入参暂时定为继承自HTTPMethod,以GET为例:
Get(path?: string, priority?: number)
-
与HTTPMethod不同的是Get第一个入参为可选,如果Get的
path
入参为空时, 可以通过检索Handler Function 名称自动匹配路径。 下面以GET为例:@Controller('/api/v1') class Fruit { // GET /api/v1/hello @Get() hello() { } }
以下方代码为例子,如果要处理当前Controller的跟路径,请使用Get('/')
@Controller('/api/v1') class Fruit { // GET /api/v1/ @Get('/') home() { } }
新增RestController修饰
- 新增RestController修饰,这个修饰器为HttpController修饰器的子类,主要是HttpController的扩展
- 基于RestController实现相关Restful 请求特性。
RESTful的独有特性
-
与常规HttpController不同,RestController将自动携带 Hypermedia, API,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。 比如访问 https://api.github.com/ 即可获得所有api 访问api.github.com/user,然后就得到了下面结果。
{ "message": "Requires authentication", "documentation_url": "https://docs.github.com/rest/reference/users#get-the-authenticated-user" }
具体能力
-
配置baseRoot对RestController的会产生影响,通过这个字段可以全局调整RESTful根路径。
//config.default.ts tegg:{ baseRoot:'/tegg' }
此时会将rest默认的
/api
前缀覆盖为/tegg
//config.default.ts tegg:{ baseRoot:'/' }
此时会将rest默认的
/api
前缀覆盖为/
-
@RestController继承自HttpController,但是与Controller不同,如果path为缺省会根据当前的class name 并以复数的形式自动补全,会在当前根目录自动生成Hypermedia API。
type RestControllerOptions { docURL?:string, version?:string, protoName?: string, controllerName?: string, } @RestController(path?: string, options?: RestControllerOptions)
以下方代码为例子,我们没有填写任何参数并且没有配置
baseRoot
字段,那么就会指向/api/v1/fruits
@RestController() class Fruit { // GET /api/v1/fruit/apple @List apple() {} }
下面我们假设进行请求
$ GET /api/v1/fruits # 我们会得到 { "apple": "/api/v1/fruits/apple" "documentation_url": "/doc/v1/fruit" }
$GET /api/v1 # 我们会得到 { "fruit": "/api/v1/fruits" "documentation_url": "/doc/v1" }
基于Get 请求增加,额外的业务能力
@Query
支持取出单条数据@Query() foo(id:string):Promise <Foo> {}
@List
支持取出所有数据,默认遵从RESTful风格支持常见参数过滤(可能需要配合ORM的能力)
1.支持 ?limit=10:指定返回记录的数量
2.支持 ?offset=10:指定返回记录的开始位置。
3.支持 ?page=2&per_page=100:指定第几页,以及每页的记录数。 4.根据函数的入参可以进行横向扩展,比如需要支持搜索
@List()
listFoo(keyword:string):Promise<Array<Foo>> {}
剩余业务能力支持待补充
新增RpcController修饰
待调查: 主要调查方向GRPC, JSONRPC
其他资料与难点调研
cc @killagu ,我把咱们讨论的问题进行了一下小结,在整理的时候发现了一点问题,我查了一下阮一峰的RESTful描述,如果要是严格按照这个描述的话,RestController的HttpMethod是否是一个就够了?我们是否要在这一个Handler里处理全部HttpMethod?
RestController 只有一个 http method 是不够的,每个动词都代表了不同的行为。不能混在一个 method 里的。
@Controller('/api/v1')
class Fruit {
// GET /api/v1/hello
@Get()
Hello() {}
}
-
Hello
方法名是否应该小写?
@Controller('/api/v1')
class Fruit {
// GET /api/v1/
@Get()
Index() {}
}
Index
会被替换为 /
。这个在方法名作为 path 的规则上又加了一个规则,有些复杂了,不如显示的写 @Get('/')
来的直接。
@Controller('/api/v1') class Fruit { // GET /api/v1/hello @Get() Hello() {} }
Hello
方法名是否应该小写?@Controller('/api/v1') class Fruit { // GET /api/v1/ @Get() Index() {} }
Index
会被替换为/
。这个在方法名作为 path 的规则上又加了一个规则,有些复杂了,不如显示的写@Get('/')
来的直接。
嗯,Hello的大小写我修改一下,第二个问题说的也有道理,确实是这样
RestController 只有一个 http method 是不够的,每个动词都代表了不同的行为。不能混在一个 method 里的。
这个能不能具体说一下,因为我平时使用RESTful比较少
rest 是以资源为维度来访问的,比如 POST 是创建一个资源, GET / 获取列表, GET /:id 是获取一个字端,PUT, DELETE 都有其含义。
rest 是以资源为维度来访问的,比如 POST 是创建一个资源, GET / 获取列表, GET /:id 是获取一个字端,PUT, DELETE 都有其含义。
如果是这样的话好像不需要RestController了吧,只需要把 path传入对应的HttpMethod就可以了
意义还是有的,也是简化。 比如说 list,get 可以写成
@RestController()
class Resource {
@List()
listFoo(): Promise<Array<Foo>> {}
@Get()
getFoo(id: string): Promise<Foo> {}
}
我去学习了一下相关内容,补充了一下RFC内容,麻烦帮忙康康有没有啥问题@killagu :relaxed:
以下方代码为例子,我们没有填写任何参数并且没有配置baseRoot字段,那么就会指向/api/v1/fruit/apple
按照 rest 风格,这个作为 /api/v1/fruits
更好,应该以资源为核心,与方法名无关。
新增的 controller
注解,可以补充一下如何 import。
@Cyberhan123 可以先来写一版 http 的。RFC 看起来不错
@Cyberhan123 可以先来写一版 http 的。RFC 看起来不错
好的~~,这个RFC也会不断完善的
最近比较忙,不过我会继续的,不会咕咕
没有进展了吗