ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
项目中通常使用 RESTful API,实现对第三方提供API服务。RESTful API 使用 HTTP 中的请求类型来标识对资源的增删改查的操作。如: |Method|URL|说明| |---|---|---| |GET| /user|获取 user列表| |GET| /user/:id|查看某个具体的 user| |POST | /user| 新建一个 user| |PUT| /user/:id| 更新指定 id 值的 user| |DELETE |/user/:id|删除指定 id 值的 user| # 创建 RESTful Controller 可以通过`-r`参数来创建 REST Controller。如: ~~~ thinkjs controller user -r ~~~ 会创建下面几个文件: ~~~ create : src/controller/rest.js create : src/controller/user.js create : src/logic/user.js ~~~ 其中`src/controller/user.js`会继承`src/controller/rest.js`类,`rest.js`是 RESTful Controller 的基类,具体的逻辑可以根据项目情况进行修改。 # 添加自定义路由 RESTful Controller 创建后并不能立即对其访问,需要添加对应的自定义路由,修改路由配置文件`src/config/router.js`,添加如下的配置: ~~~js module.exports = [ [/\/user(?:\/(\d+))?/, 'user?id=:1', 'rest'], ] ~~~ 上面自定义路由的含义为: * `/\/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 路由的话,每次都添加自定义路由势必有些麻烦,这时候可以修改一下自定义路由的配置文件,例如: ~~~js module.exports = [ [/\/api\/(\w+)(?:\/(\d+))?/, 'api/:1?id=:2', 'rest'] ]; ~~~ 这样表示所有以`/api`开头的二级路由都会被指定成 RESTful 路由。 # 实例操作 创建school的REST控制器 ~~~ thinkjs controller school -r ~~~ 会创建下面几个文件: ~~~ create : src/controller/rest.js create : src/controller/school.js create : src/logic/school.js ~~~ ## rest.js文件 文件路径:src/controller/rest.js > 已经修改默认的getAction实现,增加了分页查找的支持 ```js const assert = require('assert'); module.exports = class extends think.Controller { static get _REST() { return true; } constructor(ctx) { super(ctx); this.resource = this.getResource(); this.id = this.getId(); assert(think.isFunction(this.model), 'this.model must be a function'); this.modelInstance = this.model(this.resource); } __before() { } /** * get resource * @return {String} [resource name] */ getResource() { return this.ctx.controller.split('/').pop(); } getId() { const id = this.get('id'); if (id && (think.isString(id) || think.isNumber(id))) { return id; } const last = this.ctx.path.split('/').slice(-1)[0]; if (last !== this.resource) { return last; } return ''; } async getAction() { let data; if (this.id) { const pk = this.modelInstance.pk; data = await this.modelInstance.where({ [pk]: this.id }).find(); return this.success(data); } const page = this.get('page'); //分页参数 if (page) { const pageSize = this.get('pageSize') || 10; //分页参数 data = await this.modelInstance.page(page, pageSize).countSelect(); return this.success(data); } else { data = await this.modelInstance.select(); //不分页,检索全部记录 return this.success(data); } } /** * put resource * @return {Promise} [] */ async postAction() { const pk = this.modelInstance.pk; const data = this.post(); delete data[pk]; if (think.isEmpty(data)) { return this.fail('data is empty'); } const insertId = await this.modelInstance.add(data); return this.success({ id: insertId }); } /** * delete resource * @return {Promise} [] */ async deleteAction() { if (!this.id) { return this.fail('params error'); } const pk = this.modelInstance.pk; const rows = await this.modelInstance.where({ [pk]: this.id }).delete(); return this.success({ affectedRows: rows }); } /** * update resource * @return {Promise} [] */ async putAction() { if (!this.id) { return this.fail('params error'); } const pk = this.modelInstance.pk; const data = this.post(); data[pk] = this.id; // rewrite data[pk] forbidden data[pk] !== this.id if (think.isEmpty(data)) { return this.fail('data is empty'); } const rows = await this.modelInstance.where({ [pk]: this.id }).update(data); return this.success({ affectedRows: rows }); } __call() { } }; ``` ## 重载getAction 修改 src/controller/school.js文件 * [ ] 增加按照关键字模糊匹配 * [ ] 增加根据学校代码查找的方法接口 ```js const BaseRest = require('./rest.js'); module.exports = class extends BaseRest { async getAction() { let data; if (this.id) { const pk = this.modelInstance.pk; data = await this.modelInstance.where({ [pk]: this.id }).find(); return this.success(data); } const page = this.get('page') || 1; const pageSize = this.get('pageSize') || 10; const method = this.get('method'); if (method === 'getSchoolByCode') { //使用学校代码检索 const school_code = this.get('school_code'); data = await this.modelInstance.where({ school_code: school_code }).find(); // think.logger.debug(data) return this.success(data); } let map = {}; const key = this.get('key'); if (key) { map['title|school_code'] = ['LIKE', '%' + key + '%']; //title LIKE '%KEY%' OR school_code LIKE '%KEY%' } const page = this.get('page'); //分页参数 if (page) { const pageSize = this.get('pageSize') || 10; //分页参数 data = await this.modelInstance.where(map).page(page, pageSize).countSelect(); return this.success(data); } else { data = await this.modelInstance.where(map).select(); //不分页,检索全部记录 return this.success(data); } } }; ``` ## 修改路由配置文件 src/config/router.js ```js module.exports = [ [/\/school(?:\/(\d+))?/, 'school?id=:1', 'rest'], // 第一种方式 ]; ``` ## 调用方法 | Method | 调用实例 | | --- | --- | | GET | http://localhost:8360/school/1 | | GET | http://localhost:8360/school?page=1&pageSize=10 | | GET | http://localhost:8360/school?method=getSchoolByCode&school_code=12046 | | PUT |http://localhost:8360/school/1 | | POST|http://localhost:8360/school/1 | | DELETE|http://localhost:8360/school/1 | > PUT和POST操作需要设置POST的内容,使用JSON格式 ## 批量添加模拟数据 需要安装并引入mockjs包 ```js const Mock = require('mockjs'); ``` 执行POST请求 ``` POST http://127.0.0.1:8360/index/mock ``` ```js async mockAction() { if (this.isPost) { //生成模拟数据 let mockOption = { 'data|5': [ { //'id': '@increment()', 'school_code': '12046', //学校代码 'title|1': ['中山大学', '北京大学', '清华大学', '广州大学', '华南理工大学', '国防科技大学', '广州番禺职业技术学院'], //学校名称 'type|1': ['本科', '高职高专', '一般大专', '中专'], //学校类型 'city': '@city(true)', //学校所在城市 'address': '@county(true)', //学校地址 'cover_image_id': 1, 'cover_image': 'http://via.placeholder.com/200x150', //公司LOGO 'certified|1': ['认证学校', ''], 'description': '@cparagraph(10,20)', //公司介绍 'tags': function () { //随机选择3个标签 let array = ['双一流', '985', '示范性院校', '教育部直属', '民办高校']; array.sort(function (a, b) { return Math.random() > 0.5 ? 1 : 0; }); //简单打乱方法 let [a, b, c, ...rest] = array; return [a, b, c].join(','); }, }], }; let data = await Mock.mock(mockOption); //删除已有的数据 await this.model('school').where(true).delete(); //添加新的模拟数据 let school_code = 12046; for (let item of data.data) { item.school_code = school_code++; await this.model('school').where({ "title": item.title }).thenAdd(item); } data = await this.model('school').select(); return this.success(data); } } ```