RESTful API

项目中,经常要提供一个 API 供第三方使用,一个通用的 API 设计规范就是使用 RESTful API,RESTful API 是使用 HTTP 中的请求类型来标识对资源的操作。如:

  • GET /ticket 获取 ticket 列表
  • GET /ticket/:id 查看某个具体的 ticket
  • POST /ticket 新建一个 ticket
  • PUT /ticket/:id 更新 id 为 12 的 ticket
  • DELETE /ticket/:id 删除 id 为 12 的 ticekt

    创建 RESTful Controller

可以通过 -r 参数来创建 REST Controller。如:

  1. thinkjs controller user -r

会创建下面几个文件:

  1. create : src/controller/rest.js
  2. create : src/controller/user.js
  3. create : src/logic/user.js

其中 src/controller/user.js 会继承 src/controller/rest.js 类,rest.js 是 RESTful Controller 的基类,具体的逻辑可以根据项目情况进行修改。

添加自定义路由

RESTful Controller 创建后并不能立即对其访问,需要添加对应的自定义路由,修改路由配置文件 src/config/router.js,添加如下的配置:

  1. module.exports = [
  2. [/\/user(?:\/(\d+))?/, 'user?id=:1', 'rest'], // 第一种方式
  3. ['/user/:id?', '/user', 'rest'], // 第二种方式
  4. ['/user/:id?', 'rest'], // 第三种方式
  5. ]

注:第三种方式需要 think-router 的版本 >=1.0.17

上面自定义路由的含义为:

  • /\/user(?:\/(\d+))?/ URL 的正则
  • user?id=:1 映射后要解析的路由,:1 表示取正则里的 (\d+) 的值
  • rest 表示为 REST API
    通过自定义路由,将 /user/:id 相关的请求指定为 REST Controller,然后就可以对其访问了。

  • GET /user 获取用户列表,执行 getAction

  • GET /user/:id 获取某个用户的详细信息,执行 getAction
  • POST /user 添加一个用户,执行 postAction
  • PUT /user/:id 更新一个用户,执行 putAction
  • DELETE /user/:id 删除一个用户,执行 deleteAction
    如果有一系列路由都是 RESTful 路由的话,每次都添加自定义路由势必有些麻烦,这时候可以修改一下自定义路由的配置文件,例如:
  1. module.exports = [
  2. [/\/api\/(\w+)(?:\/(\d+))?/, 'api/:1?id=:2', 'rest']
  3. ];

这样表示所有以 /api 开头的二级路由都会被指定成 RESTful 路由。

数据校验

Controller 里的方法执行时并不会对传递过来的数据进行校验,数据校验可以放在 Logic 里处理,文件为 src/logic/user.js,具体的 Action 与 Controller 里一一对应。具体的使用方式请见 Logic

子级 RESTful API

有时候有子级 RESTful API,如:某篇文章的评论接口,这时候可以通过下面的自定义路由完成:

  1. module.exports = [
  2. [/\/post\/(\d+)\/comments(?:\/(\d+))?/, 'comment?postId=:1&id=:2', 'rest']
  3. ]

这样在对应的 Action 里,可以通过 this.get("postId") 来获取文章的 id,然后放在过滤条件里处理即可。

  1. const Rest = require('./rest.js');
  2. module.exports = class extends Rest {
  3. async getAction() {
  4. const postId = this.get('postId');
  5. const commentId = this.get('id');
  6. const comment = this.model('comment');
  7. if(commentId) { // 获取单条评论的详细信息
  8. const data = await comment.where({post_id: postId, id: commentId}).find();
  9. return this.success(data);
  10. } else { // 获取单条文章下的评论列表
  11. const list = await comment.where({post_id: postId}).select();
  12. return this.success(list);
  13. }
  14. }
  15. }

多版本 RESTful API

有些 REST API 有时候前后不能完全兼容,需要有多个版本,这时候也可以通过自定义路由管理,如:

  1. module.exports = [
  2. [/\/v1\/user(?:\/(\d+))?/, 'v1/user?id=:1', 'rest'], //v1 版本
  3. [/\/v2\/user(?:\/(\d+))?/, 'v2/user?id=:1', 'rest'] //v2 版本
  4. ]

这时候只要在 src/controller/ 下建立子目录 v1/v2/ 即可,执行时会自动查找,具体见 多级控制器

Mongo 的 RESTful API

由于 Mongo 的 id 并不是纯数字的,所以处理 Mongo 的 RESTful API 时只需要修改下对应的正则即可(将 \d 改为 \w):

  1. module.exports = [
  2. [/\/user(?:\/(\w+))?/, 'user?id=:1', 'rest']
  3. ]

常见问题

怎么查看 RESTful API 的自定义路由已经生效?

有时候添加 RESTful Controller 和自定义路由后,访问并没有生效,这时候可以通过 DEBUG=think-router npm start 启动服务查看解析后的 controller 和 action 看其是否生效,具体请见怎么查看当前地址解析后的 controller 和 action 分别对应什么?

原文: https://thinkjs.org/zh-cn/doc/3.0/rest.html