淺談KOA2 Restful方式路由初探
阿新 • • 發佈:2019-04-11
outer 根據 集合 pes str readdir 選擇 淺談 types
前言
最近考慮將服務器資源整合一下,作為多端調用的API
看到Restful標準和ORM眼前一亮,但是找了不少版本路由寫的都比較麻煩,於是自己折騰了半天
API庫結構
考慮到全部對象置於頂層將會造成對象名越來長,同時不便於維護,故采取部分的分層結構
如workflow模塊內的prototypes,instances等等,分層的深度定義為層級
可訪問的對象集合(collection)的屬性滿足Restful設計
?1 2 3 4 5 6 7 8 9 10 |
-- workflow(category)
-- prototypes(collection) -- [method] ...
-- [method] ...
-- instances(collection)
-- users(collection)
--[method] List #get :object/
--[method] Instance #get :object/:id
-- ...
-- ...
|
RESTFUL API 接口
將Restful API接口進行標準化命名
?1 2 3 4 5 6 7 8 9 10 |
.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對象
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
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對象
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
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
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
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
淺談KOA2 Restful方式路由初探