浅谈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 相关文章推荐
[全兼容哦]--实用、简洁、炫酷的页面转入效果loing
May 07 Javascript
Javascript 强制类型转换函数
May 17 Javascript
30个最好的jQuery 灯箱插件分享
Apr 25 Javascript
javascript基础知识
Jun 07 Javascript
js内置对象处理_打印学生成绩单的简单实现
Sep 24 Javascript
js实现登录框鼠标拖拽效果
Mar 09 Javascript
解决Vue使用mint-ui loadmore实现上拉加载与下拉刷新出现一个页面使用多个上拉加载后冲突问题
Nov 07 Javascript
JS使用Date对象实时显示当前系统时间简单示例
Aug 23 Javascript
js获取对象,数组所有属性键值(key)和对应值(value)的方法示例
Jun 19 Javascript
ES6 Iterator接口和for...of循环用法分析
Jul 31 Javascript
关于在LayUI中使用AJAX提交巨坑记录
Oct 25 Javascript
前端开发之便利店收银系统代码
Dec 27 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
全国FM电台频率大全 - 10 江苏省
2020/03/11 无线电
默默小谈PHP&amp;MYSQL分页原理及实现
2007/01/02 PHP
基于PHP常用函数的用法详解
2013/05/10 PHP
PHP中的str_repeat函数在JavaScript中的实现
2013/09/16 PHP
ThinkPHP 3.2 数据分页代码分享
2014/10/14 PHP
PHP QRCODE生成彩色二维码的方法
2016/05/19 PHP
屏蔽网页右键复制和ctrl+c复制的js代码
2013/01/04 Javascript
兼容IE和FF的图片上传前预览js代码
2013/05/28 Javascript
jquery插件冲突(jquery.noconflict)解决方法分享
2014/03/20 Javascript
jquery判断浏览器后退时候弹出消息的方法
2014/08/11 Javascript
Javascript 实现图片无缝滚动
2014/12/19 Javascript
javascript中parseInt()函数的定义和用法分析
2014/12/20 Javascript
jQuery搜索子元素的方法
2015/02/10 Javascript
jQuery事件绑定on()、bind()与delegate() 方法详解
2015/06/03 Javascript
jQuery实现公告新闻自动滚屏效果实例代码
2016/07/14 Javascript
javascript特效实现——当前时间和倒计时效果的简单实例
2016/07/20 Javascript
Node.js中路径处理模块path详解
2016/11/14 Javascript
Nodejs进阶:基于express+multer的文件上传实例
2016/11/21 NodeJs
原生javascript实现图片放大镜效果
2017/01/18 Javascript
AngularJS中$http的交互问题
2017/03/29 Javascript
详解webpack+express多页站点开发
2017/12/22 Javascript
微信小程序分享功能之按钮button 边框隐藏和点击隐藏
2018/06/14 Javascript
javascript中call()、apply()的区别
2019/03/21 Javascript
vue路由切换之淡入淡出的简单实现
2019/10/31 Javascript
[02:46]2014DOTA2国际邀请赛 选手为你解读比赛MVP充满梦想
2014/07/09 DOTA
[46:44]VG vs TNC Supermajor小组赛B组败者组决赛 BO3 第一场 6.2
2018/06/03 DOTA
Python处理文本文件中控制字符的方法
2017/02/07 Python
从CentOS安装完成到生成词云python的实例
2017/12/01 Python
python实现向微信用户发送每日一句 python实现微信聊天机器人
2019/03/27 Python
Python列表操作方法详解
2020/02/09 Python
AmazeUI图片轮播效果的示例代码
2020/08/20 HTML / CSS
泰国综合购物网站:Lazada泰国
2018/04/09 全球购物
社区包粽子活动方案
2014/01/21 职场文书
区三好学生主要事迹
2014/01/30 职场文书
优秀党员个人总结
2015/02/14 职场文书
行政人事专员岗位职责
2015/04/07 职场文书