浅谈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 相关文章推荐
javascript让setInteval里的函数参数中的this指向特定的对象
Jan 31 Javascript
jquery(live)中File input的change方法只起一次作用的解决办法
Oct 21 Javascript
jQuery实现拖拽效果插件的方法
Mar 23 Javascript
基于javascript实现样式清新图片轮播特效
Mar 30 Javascript
Javascript之Number对象介绍
Jun 07 Javascript
vue多级多选菜单组件开发
Sep 08 Javascript
jQuery实现字符串全部替换的方法
Dec 12 Javascript
axios post提交formdata的实例
Mar 16 Javascript
解决vue2 在mounted函数无法获取prop中的变量问题
Nov 15 Javascript
小程序两种滚动公告栏的实现方法
Sep 17 Javascript
Vue的生命周期操作示例
Sep 17 Javascript
Vue全局事件总线你了解吗
Feb 24 Vue.js
详解微信小程序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获取网页中图片、DIV内容的简单方法
2014/06/19 PHP
Zend Guard使用指南及问题处理
2015/01/07 PHP
WordPress中使主题支持小工具以及添加插件启用函数
2015/12/22 PHP
PHP数组函数array_multisort()用法实例分析
2016/04/02 PHP
PHP实现微信小程序用户授权的工具类示例
2019/03/05 PHP
javascript中xml操作实现代码
2011/11/21 Javascript
js实现快速分享功能(你的文章分享工具)
2013/06/25 Javascript
JS中window.open全屏命令解析及使用示例
2013/12/11 Javascript
chrome不支持form.submit的解决方案
2015/04/28 Javascript
Bootstrap的图片轮播示例代码
2015/08/31 Javascript
jQuery实现的鼠标滑过弹出放大图片特效
2016/01/08 Javascript
详解Bootstrap各式各样的按钮(推荐)
2016/12/13 Javascript
angular+ionic 的app上拉加载更新数据实现方法
2017/01/16 Javascript
jQuery控制元素隐藏和显示
2017/03/03 Javascript
详解Vue的computed(计算属性)使用实例之TodoList
2017/08/07 Javascript
微信小程序使用map组件实现解析经纬度功能示例
2019/01/22 Javascript
微信小程序实现炫酷的弹出式菜单特效
2019/01/28 Javascript
小程序实现可拖动的悬浮按钮
2020/09/07 Javascript
使用Vue实现一个树组件的示例
2020/11/06 Javascript
[29:59]完美世界DOTA2联赛PWL S3 Forest vs access 第二场 12.11
2020/12/13 DOTA
python 爬取学信网登录页面的例子
2019/08/13 Python
python编写softmax函数、交叉熵函数实例
2020/06/11 Python
keras输出预测值和真实值方式
2020/06/27 Python
详解python中的lambda与sorted函数
2020/09/04 Python
Html5如何唤起百度地图App的方法
2019/01/27 HTML / CSS
澳大利亚自然和有机的健康美容产品一站式商店:Ziani Beauty
2017/12/28 全球购物
英国领先的票务代理商之一:The Ticket Factory
2019/02/09 全球购物
教师评优的个人自我评价分享
2013/09/19 职场文书
结婚喜宴家长答谢词
2014/01/15 职场文书
创业计划书的主要内容有哪些
2014/01/29 职场文书
城市轨道交通工程职业生涯规划书范文
2014/09/16 职场文书
小学教师自我剖析材料
2014/09/29 职场文书
大学同学聚会感言
2015/07/30 职场文书
幼儿园教师管理制度
2015/08/05 职场文书
小学语文教学随笔
2015/08/14 职场文书
Python如何解决secure_filename对中文不支持问题
2021/07/16 Python