当前位置: 首页 > 后端技术 > Node.js

KOA2Restful路由初探

时间:2023-04-03 23:46:43 Node.js

前言最近在考虑整合服务器资源。作为一个多端调用的API,看到了Restful标准和ORM,但是找了很多版本写路由很麻烦,自己折腾了半天。考虑到API库的结构在顶层,对象名会越来越长,而且不容易维护。因此,在工作流模块中采用了原型、实例等部分层次结构。图层的深度定义为该图层的可访问对象集合(collection)的属性。满足Restful设计--工作流(类别)--原型(集合)--[方法]...--[方法]...--实例(集合)--用户(集合)--[方法]List#get:object/--[method]Instance#get:object/:id--...--...RESTFULAPI接口规范了RestfulAPI接口的命名。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('/:对象/:id/:相关/:relatedId',RestfulAPIMethods.DelRelated)APIobject该文件来自微信小程序demo。使用方便,放在需要引用的根目录下,直接获取文件目录结构API对象const_=require('lodash')constfs=require('fs')constpath=require('path')/***将d文件夹下的文件映射为模块*/constmapDir=d=>{consttree={}//获取当前文件夹下的所有文件夹和文件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}})returntree}//默认情况下,映射下currentfolderisexportedmodule.exports=mapDir(path.join(__dirname))koa-router分层路由的实现创建多层路由及其传递关系执行顺序为1--路径匹配--匹配到'结尾/'--匹配到对应的RestfulAPI执行结束--continue2--调用中间件Nest3--下一级路由4--循环到1constDefinedRouterDepth=2letrouters=[]for(leti=0;i{//根据版本号选择库letapiVersion=ctx.headers['api-version']ctx.debug(`--------(APIversion[${apiVersion}])--=------`)if(!apiVersion){ctx.error('未标记版本号')return}letAPIRoot=nulltr??y{APIRoot=require(`../restful/${apiVersion}`)}catch(e){ctx.error('API不存在,请检查Header中的版本号')return}ctx.debug(APIRoot)ctx.apiRoot=APIRootctx.debug('------------------------------------------')//for(leti=0;i<)awaitnext()})}route.get('/',ctx=>{ctx.error('路径匹配失败')}).get('/:object',宁静APIthods.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){路由.use('/:object',Nest,routers[i-1].routes())}routers.push(route)}let=router=routers[routers.length-1]Nest中间件将ctx.apiObject设置为当前层的API对象constNest=async(ctx,next)=>{letobject=ctx.params.objectletapiObject=ctx.apiObject||ctx.apiRootif(!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}awaitnext()}RestfulAPIMethodsletRestfulAPIMethods={}letMethods=['List','Get','发布','替换','补丁','删除','相关','AddRelated','DelRelated']for(leti=0;i