当前位置: 移动技术网 > IT编程>开发语言>JavaScript > 浅谈KOA2 Restful方式路由初探

浅谈KOA2 Restful方式路由初探

2019年03月17日  | 移动技术网IT编程  | 我要评论
前言 最近考虑将服务器资源整合一下,作为多端调用的api 看到restful标准和orm眼前一亮,但是找了不少版本路由写的都比较麻烦,于是自己折腾了半天 ap

前言

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

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

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网