浅谈KOA2 Restful方式路由初探


Posted in Javascript onMarch 14, 2019

前言

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

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

Javascript 相关文章推荐
jQuery live( type, fn ) 委派事件实现
Oct 11 Javascript
通过百度地图获取公交线路的站点坐标的js代码
May 11 Javascript
jquery三个关闭弹出层的小示例
Nov 05 Javascript
在每个匹配元素的外部插入新元素的方法
Dec 20 Javascript
localResizeIMG先压缩后使用ajax无刷新上传(移动端)
Aug 11 Javascript
Extjs让combobox写起来简洁又漂亮
Jan 05 Javascript
javascript获取以及设置光标位置
Feb 16 Javascript
JS中使用 after 伪类清除浮动实例
Mar 01 Javascript
jQuery is not defined 错误原因与解决方法小结
Mar 19 Javascript
bootstrap3-dialog-master模态框使用详解
Aug 22 Javascript
微信小程序通过保存图片分享到朋友圈功能
May 24 Javascript
详解swiper在vue中的应用(以3.0为例)
Sep 20 Javascript
详解微信小程序scroll-view横向滚动的实践踩坑及隐藏其滚动条的实现
Mar 14 #Javascript
详解React项目中碰到的IE问题
Mar 14 #Javascript
Node.js + express实现上传大文件的方法分析【图片、文本文件】
Mar 14 #Javascript
React+Antd+Redux实现待办事件的方法
Mar 14 #Javascript
Node.js + express基本用法教程
Mar 14 #Javascript
Vue渲染过程浅析
Mar 14 #Javascript
详解关于JSON.parse()和JSON.stringify()的性能小测试
Mar 14 #Javascript
You might like
php中如何使对象可以像数组一样进行foreach循环
2013/08/09 PHP
php+mysql不用递归实现的无限级分类实例(非递归)
2014/07/08 PHP
php利用header函数下载各种文件
2016/08/24 PHP
PHP多个图片压缩成ZIP的方法
2020/08/18 PHP
阿里对象存储OSS在laravel框架中的使用方法
2019/10/13 PHP
WebGame《逆转裁判》完整版 代码下载(1月24日更新)
2007/01/29 Javascript
JavaScript基本编码模式小结
2012/05/23 Javascript
JS.getTextContent(element,preformatted)使用介绍
2013/09/21 Javascript
jQuery简单实现banner图片切换
2014/01/02 Javascript
JavaScript中使用Math.floor()方法对数字取整
2015/06/15 Javascript
Javascript显示和隐藏ul列表的方法
2015/07/15 Javascript
如何用jQuery实现ASP.NET GridView折叠伸展效果
2015/09/26 Javascript
使用JS组件实现带ToolTip验证框的实例代码
2017/08/23 Javascript
用p5.js制作烟花特效的示例代码
2018/03/21 Javascript
jQuery的Ajax接收java返回数据方法
2018/08/11 jQuery
在vue中使用SockJS实现webSocket通信的过程
2018/08/29 Javascript
js判断非127开头的IP地址的实例代码
2020/01/05 Javascript
vue实现简单的登录弹出框
2020/10/26 Javascript
解决antd datepicker 获取时间默认少8个小时的问题
2020/10/29 Javascript
React Ant Design树形表格的复杂增删改操作
2020/11/02 Javascript
[01:08:00]Fnatic vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
Python写的Tkinter程序屏幕居中方法
2015/03/10 Python
利用Python查看微信共同好友功能的实现代码
2019/04/24 Python
Pycharm最新激活码2019(推荐)
2019/12/31 Python
使用matplotlib的pyplot模块绘图的实现示例
2020/07/12 Python
python 实现图片修复(可用于去水印)
2020/11/19 Python
HTML5之SVG 2D入门5—颜色的表示及定义方式
2013/01/30 HTML / CSS
匈牙利超级网上商店和优惠:Alza.hu
2019/12/17 全球购物
国庆节演讲稿
2014/05/27 职场文书
大学毕业典礼演讲稿
2014/09/09 职场文书
2014年学校党建工作总结
2014/11/11 职场文书
就业推荐表导师评语
2014/12/31 职场文书
银行求职信范文怎么写
2015/03/20 职场文书
微信小程序中wxs文件的一些妙用分享
2022/02/18 Javascript
python中 .npy文件的读写操作实例
2022/04/14 Python
golang连接MySQl使用sqlx库
2022/04/14 Golang