前言
最近考虑将服务器资源整合一下,作为多端调用的API
看到Restful标准和ORM眼前一亮,但是找了不少版本路由写的都比较麻烦,于是自己折腾了半天
API库结构
考虑到全部对象置于顶层将会造成对象名越来长,同时不便于维护,故采取部分的分层结构
如workflow模块内的prototypes,instances等等,分层的深度定义为层级
可访问的对象集合(collection)的属性满足Restful设计
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
 | 
-- workflow(category) -- prototypes(collection)   -- [method] ...   -- [method] ...  -- instances(collection)-- users(collection)  --[method] List     #get :object/  --[method] Instance   #get :object/:id-- ...-- ... | 
RESTFUL API 接口
将Restful API接口进行标准化命名
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
 | 
.get(‘/‘, ctx=>{ctx.error(‘路径匹配失败‘)})        .get(‘/:object‘, RestfulAPIMethods.List).get(‘/:object/:id‘, RestfulAPIMethods.Get).post(‘/:object‘, RestfulAPIMethods.Post).put(‘/:object/:id‘, RestfulAPIMethods.Replace).patch(‘/:object/:id‘, RestfulAPIMethods.Patch).delete(‘/:object/:id‘, RestfulAPIMethods.Delete).get(‘/:object/:id/:related‘, RestfulAPIMethods.Related).post(‘/:object/:id/:related‘, RestfulAPIMethods.AddRelated).delete(‘/:object/:id/:related/:relatedId‘, RestfulAPIMethods.DelRelated) | 
API对象
这个文件是来自微信小程序demo,觉得很方便就拿来用了,放于需要引用的根目录,引用后直接获得文件目录结构API对象
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
 | 
const _ = require(‘lodash‘)const fs = require(‘fs‘)const path = require(‘path‘)/** * 映射 d 文件夹下的文件为模块 */const mapDir = d => {  const tree = {}  // 获得当前文件夹下的所有的文件夹和文件  const [dirs, files] = _(fs.readdirSync(d)).partition(p => fs.statSync(path.join(d, p)).isDirectory())  // 映射文件夹  dirs.forEach(dir => {    tree[dir] = mapDir(path.join(d, dir))  })  // 映射文件  files.forEach(file => {    if (path.extname(file) === ‘.js‘) {      tree[path.basename(file, ‘.js‘)] = require(path.join(d, file))      tree[path.basename(file, ‘.js‘)].isCollection = true    }  })  return tree}// 默认导出当前文件夹下的映射module.exports = mapDir(path.join(__dirname)) | 
koa-router分层路由的实现
创建多层路由及其传递关系
执行顺序为
 1 -- 路径匹配
    -- 匹配到‘/‘结束
    -- 匹配到对应的RestfulAPI执行并结束
    -- 继续
 2 -- 传递中间件 Nest
 3 -- 下一级路由 
 4 -- 循环 to 1
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
 | 
const DefinedRouterDepth = 2let routers = []for (let i = 0; i < DefinedRouterDepth; i++) {  let route = require(‘koa-router‘)()  if (i == DefinedRouterDepth - 1) {    // 嵌套路由中间件    route.use(async (ctx, next) => {      // 根据版本号选择库      let apiVersion = ctx.headers[‘api-version‘]      ctx.debug(`------- (API版本 [${apiVersion}]) --=-------`)       if (!apiVersion) {        ctx.error(‘版本号未标记‘)        return      }      let APIRoot = null      try {        APIRoot = require(`../restful/${apiVersion}`)      } catch (e) {        ctx.error (‘API不存在,请检查Header中的版本号‘)        return      }      ctx.debug(APIRoot)      ctx.apiRoot = APIRoot      ctx.debug(‘---------------------------------------------‘)      // for(let i=0;i<)      await next()    })  }  route    .get(‘/‘, ctx=>{ctx.error(‘路径匹配失败‘)})    .get(‘/:object‘, RestfulAPIMethods.List)    .get(‘/:object/:id‘, RestfulAPIMethods.Get)    .post(‘/:object‘, RestfulAPIMethods.Post)    .put(‘/:object/:id‘, RestfulAPIMethods.Replace)    .patch(‘/:object/:id‘, RestfulAPIMethods.Patch)    .delete(‘/:object/:id‘, RestfulAPIMethods.Delete)    .get(‘/:object/:id/:related‘, RestfulAPIMethods.Related)    .post(‘/:object/:id/:related‘, RestfulAPIMethods.AddRelated)    .delete(‘/:object/:id/:related/:relatedId‘, RestfulAPIMethods.DelRelated)  if (i != 0) {    route.use(‘/:object‘, Nest, routers[i - 1].routes())  }  routers.push(route)}let = router = routers[routers.length - 1] | 
Nest中间件
将ctx.apiObject设置为当前层的API对象
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
 | 
const Nest= async (ctx, next) => {  let object = ctx.params.object  let apiObject = ctx.apiObject || ctx.apiRoot  if(!apiObject){    ctx.error(‘API装载异常‘)    return  }  if (apiObject[object]) {    ctx.debug(`ctx.apiObject=>ctx.apiObject[object]`)    ctx.debug(apiObject[object])    ctx.debug(`------------------------------------`)    ctx.apiObject = apiObject[object]  } else {    ctx.error(`API接口${object}不存在`)    return  }  await next()} | 
RestfulAPIMethods
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
 | 
let RestfulAPIMethods = {}let Methods = [‘List‘, ‘Get‘, ‘Post‘, ‘Replace‘, ‘Patch‘, ‘Delete‘, ‘Related‘, ‘AddRelated‘, ‘DelRelated‘]for (let i = 0; i < Methods.length; i++) {  let v = Methods[i]  RestfulAPIMethods[v] = async function (ctx, next) {         let apiObject = ctx.apiObject || ctx.apiRoot    if (!apiObject) {      ctx.error (‘API装载异常‘)      return    }    let object = ctx.params.object    if (apiObject[object] && apiObject[object].isCollection) {      ctx.debug(` --- Restful API [${v}] 调用--- `)      if (typeof apiObject[object][v] == ‘function‘) {        ctx.state.data = await apiObject[object][v](ctx)        ctx.debug(‘路由结束‘)        return        //ctx.debug(ctx.state.data)      } else {        ctx.error(`对象${object}不存在操作${v}`)        return      }    }    ctx.debug(` --- 当前对象${object}并不是可访问对象 --- `)    await next()  }} | 
需要注意的点
1、koa-router的调用顺序
2、涉及到async注意next()需要加await
原文:https://www.cnblogs.com/lorelei123/p/10688832.html