前言
最近考虑将服务器资源整合一下,作为多端调用的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 = 2 let 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