JavaScript

超轻量级php框架startmvc

浅谈KOA2 Restful方式路由初探

更新时间:2020-08-18 05:00:01 作者:startmvc
前言最近考虑将服务器资源整合一下,作为多端调用的API看到Restful标准和ORM眼前一亮,但是

前言

最近考虑将服务器资源整合一下,作为多端调用的API

看到Restful标准和ORM眼前一亮,但是找了不少版本路由写的都比较麻烦,于是自己折腾了半天

API库结构

考虑到全部对象置于顶层将会造成对象名越来长,同时不便于维护,故采取部分的分层结构

如workflow模块内的prototypes,instances等等,分层的深度定义为层级

可访问的对象集合(collection)的属性满足Restful设计


 -- workflow(category)
 -- prototypes(collection)
 -- [method] ...
 -- [method] ... 
 -- instances(collection)
 -- users(collection)
 --[method] List #get :object/
 --[method] Instance #get :object/:id
 -- ...
 -- ...

RESTFUL API 接口

将Restful API接口进行标准化命名


.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对象


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


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对象


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


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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

KOA2 Restful 路由 KOA2 Restful