swagger-decorator:为Koa2应用动态生成Swagger文档的注解方式,接口文档,在线质量监控越来越突出。本文主要讨论接口文件的实时发布;在前后端分离的今天,即使一个人垂直负责某个业务流程,也需要明确定义和发布前后端交互的接口规范,以确保项目透明度和可维护性。在理想的开发过程中,关键字段的命名、数据库表的设计、接口文档应该在产品设计阶段就确定下来;但在实际操作中,由于业务多变和缺乏人力,接口的定义并不总是实时完成的。在项目成员之间建立共识。如果要求开发人员在更改接口的同时花费额外的精力去维护一个开发文档,对于我们这样的小公司来说可能成本和风险都很大。软件开发中有一个所谓的SingleSourceofTruth原则,我们也需要尽量避免团队内部的冲突,避免因文档与实际实现不一致而造成的无用功。综上所述,我们希望能够在编写后台代码和添加注解的同时,自动生成接口文档;笔者比较熟悉Spring中注解添加Swagger文档的模式,但Java类库的抽象度普遍较高。起床并不容易。作者正在编写我们公司的node-server-boilerplate,按照自己的想法设计了swagger-decorator。此外,该项目使用Flow进行静态类型检查,并遵循我们内部的JavaScript编程风格指南。我们可以使用npm或yarn来安装swagger-decorator。需要注意的是,因为使用了注解,所以建议配置Webpack和Babel。不熟悉的同学可以直接参考node-server-boilerplate:$yarnaddswagger-decorator#依赖于Babel的transform-decorators-legacy转换插件来使用Decorator$yarnaddtransform-decorators-legacy-D安装后我们需要封装项目中使用的路由。目前笔者只是将路由对象封装在koa-router中。如果有需要,以后可以封装其他框架的路由方案。我们首先要做的是在路由定义前使用wrappingKoaRouter函数修改路由器对象:import{wrappingKoaRouter}from"swagger-decorator";...constRouter=require("koa-router");constrouter=newRouter();wrappingKoaRouter(router,"localhost:8080","/api",{title:"NodeServerBoilerplate",version:"0.0.1",description:"Koa2,koa-router,Webpack"});//定义默认根路由router.get("/",asyncfunction(ctx,next){ctx.body={msg:"NodeServerBoilerplate"};});//定义用户处理路由router.scan(UserController);该函数的参数如下,forinfo的结构在这里:/***说明封装了router对象的方法*@paramrouter路由对象*@paramhostAPI域名*@parambasePathAPI基本路径*@paraminfo其他Swagger基本信息*/exportfunctionwrappingKoaRouter(router:Object,host:string="localhost",basePath:string="",info:Object={}){}值得一提的是,在封装router的时候,作者自定义了scan方法,可以根据self定义一个方法自动遍历目标类,有点类似Java中的ComponentScan:/***说明扫描一个类中的所有静态方法,并添加到*@paramstaticClass*/router.scan=function(静态类:Function){letmethods=Object.getOwnPropertyNames(staticClass);//去掉前三个属性构造函数,namemethods.shift();methods.shift();methods.shift();for(letmethodofmethods){router.all(staticClass[方法]);}};准备工作完成后,我们就可以开始定义具体的接口控制器了;我不喜欢过多的封装,所以这里我选择了类的静态方法来定义具体的接口函数,整个Controller也只是一个朴素的函数下面笔者列举了获取所有用户列表、根据用户编号获取用户详情、创建新用户的常用文档注解方法:"../entity/User";/***描述用户相关控制器*/exportdefaultclassUserController{@apiRequestMapping("get","/users")@apiDescription("getalluserslist")@apiResponse(200,"getuserssuccessfully",[用户])staticasyncgetUsers(ctx,next):[用户]{...}@apiRequestMapping("get","/user/:id")@apiDescription("getuserobjectbyid,onlyaccessselfforfriends")@pathParameter({name:"id",description:"userid",type:"integer"})@queryParameter({name:"tags",description:"usertags,forfilteringusers",required:false,type:"array",items:["字符串"]})@apiResponse(200,"getusersuccessfully",User)staticasyncgetUserByID(ctx,next):User{...}@apiRequestMapping("post","/user")@apiDescription("createnewuser")@bodyParameter({name:"user",description:"thenewuserobject,mustincludeusername",required:true,schema:User})@apiResponse(200,"createnewusersuccessfully",{status_code:"200"})staticasyncpostUser():number{...}}在注解接口的时候,我们需要用实体类来表示返回值或者请求体中包含的参数信息,所以我们也有必要使用swagger-decorator提供的entityProperty注解来为实体类添加描述。值得一提的是,这里我们支持直接使用Object作为描述对象的返回值,避免了Java中的一大痛点。//@f??lowimport{entityProperty}from"swagger-decorator";/***描述用户实体类*/exportdefaultclassUser{//Number@entityProperty({type:"integer",description:"userid,auto-generated",required:false})id:string=0;//name@entityProperty({type:"string",description:"username,3~12characters",required:true})name:string="name";//好友列表friends:[number]=[1];//Attributeproperties:{address:string}={address:"address"};}对于没有注解的属性,swagger-decorator会根据其默认值自动推断类型。然后我们就可以正常启动应用了,swagger-decorator已经自动给router对象添加了两条路由,其中??/swagger指向SwaggerUI:和/swagger/api.json指向Swagger生成的JSON文档:【这篇文章是专栏作者“张子雄”原创文章,如需转载,请通过]联系作者]点此查看该作者更多好文
