浅谈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 相关文章推荐
用apply让javascript函数仅执行一次的代码
Jun 27 Javascript
PHP 与 js的通信(via ajax,json)
Nov 16 Javascript
Js,alert出现乱码问题的解决方法
Jun 19 Javascript
javascript面向对象特性代码实例
Jun 12 Javascript
SuperSlide标签切换、焦点图多种组合插件
Mar 14 Javascript
jQuery实现的多滑动门,多选项卡效果代码
Mar 28 Javascript
微信小程序实现文字跑马灯效果
May 26 Javascript
微信小程序项目实践之主页tab选项实现
Jul 18 Javascript
Vuejs监听vuex中值的变化的方法示例
Dec 02 Javascript
javascript面向对象三大特征之继承实例详解
Jul 24 Javascript
wx-charts 微信小程序图表插件的具体使用
Aug 18 Javascript
easyUI 实现的后台分页与前台显示功能示例
Jun 01 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
Linux下进行MYSQL编程时插入中文乱码的解决方案
2007/03/15 PHP
PHP警告Cannot use a scalar value as an array的解决方法
2012/01/11 PHP
PHP中VC6、VC9、TS、NTS版本的区别与用法详解
2013/10/26 PHP
超详细的php用户注册页面填写信息完整实例(附源码)
2015/11/17 PHP
php pthreads多线程的安装与使用
2016/01/19 PHP
各种快递查询--Api接口
2016/04/26 PHP
使用JQuery进行跨域请求
2010/01/25 Javascript
js判断字符长度以及中英文数字等
2013/12/31 Javascript
JavaScript在IE和FF下的兼容性问题
2014/05/19 Javascript
node.js中的fs.fstat方法使用说明
2014/12/15 Javascript
JavaScript实现MIPS乘法模拟的方法
2015/04/17 Javascript
跨域资源共享 CORS 详解
2016/04/26 Javascript
jQuery实现键盘回车搜索功能
2017/07/25 jQuery
jQuery实现IE输入框完成placeholder标签功能的方法
2017/09/20 jQuery
Vue实现左右菜单联动实现代码
2018/08/12 Javascript
JavaScript使用类似break机制中断forEach循环的方法
2018/11/13 Javascript
vue-cli3单页构建大型项目方案
2020/04/07 Javascript
python中查找excel某一列的重复数据 剔除之后打印
2013/02/10 Python
Python中利用sorted()函数排序的简单教程
2015/04/27 Python
python在Windows下安装setuptools(easy_install工具)步骤详解
2016/07/01 Python
Python环境搭建之OpenCV的步骤方法
2017/10/20 Python
Python测试网络连通性示例【基于ping】
2018/08/03 Python
对Python中创建进程的两种方式以及进程池详解
2019/01/14 Python
python实现烟花小程序
2019/01/30 Python
pybind11在Windows下的使用教程
2019/07/04 Python
wxPython多个窗口的基本结构
2019/11/19 Python
Python异常原理及异常捕捉实现过程解析
2020/03/25 Python
基于Python计算圆周率pi代码实例
2020/03/25 Python
python如何导出微信公众号文章方法详解
2020/08/31 Python
英国亚马逊官方网站:Amazon.co.uk
2019/08/09 全球购物
教师实习自我鉴定
2013/12/11 职场文书
2015年元宵节活动总结
2015/02/06 职场文书
新生儿未入户证明
2015/06/23 职场文书
选对餐饮营销策略,营业额才会上涨
2019/08/27 职场文书
MySQL分库分表详情
2021/09/25 MySQL
Elasticsearch 索引操作和增删改查
2022/04/19 Python