【go语言微服务实践】#4-beego和go-micro自动化生成API文档

1,888 阅读6分钟

线上答题系统,微服务架构的小小实践,项目代码

一、概述

  单体应用在改造成微服务架构后,模块与模块间的交互会变得复杂,功能增多,接口也会增多,因此十分有必要维护一份系统的API接口说明。答题系统从上到下分为view、controller、service、model四层,controller和前端view之间使用REST API交互,因此使用目前比较流行的swagger进行接口维护。controller和service之间是RPC接口,使用的是protocol buffers协议,可以使用protoc-gen-doc工具直接生成rpc接口说明的html页面。

**技术选型**
前端view层:planeui+jquery
controller层(页面逻辑处理):beego
service层:go-micro
model层:beego的orm
REST API展示:swagger
RPC API展示:protoc-gen-doc

二、beego与swagger

  Beego支持自动化生成swagger API文档,只需要按语法规则在routers/router.go中配置好路由 ,并在对应的cotroller方法写好路由注释。以用户的CURD为例:

  1. 全局路由配置

  在routers/router.go最顶部注释

// @APIVersion 1.0.0
// @Title mobile API
// @Description mobile has every tool to get any job done, so codename for the new mobile APIs.
// @Contact astaxie@gmail.com
package routers

  目前自动化文档只支持如下的写法的解析,其他写法函数不会自动解析,即 namespace+Include 的写法,而且只支持二级解析,一级版本号,二级分别表示应用模块。因此/v1/users的请求对应UserManageController。

func init() {
   ns :=
      beego.NewNamespace("/v1",
         beego.NSNamespace("/users",
            beego.NSInclude(
               &controllers.UserManageController{},
            ),
         ),
      )
   beego.AddNamespace(ns)
}
  1. 应用注释

  在REST API对应的方法前进行路由注释,即可让请求匹配该方法。如新增用户,当以POST请求访问/v1/users时,就会执行UserManageController.AddUser方法。删除用户,则是DELETE方法访问/v1/users,最终执行DeleteUserById,删除的用户id可从request payload中获取。获取用户是GET方法访问,修改用户信息是PUT方法访问,最终分别执行GetUser和ChangeUser方法。

package controllers

type UserManageController struct {
    beego.Controller
}
// @Title 新增用户
// @Description 新增用户
// @Param  user_name  formData   string false  "用户名"
// @Param  login_name formData   string false  "用户登陆名"
// @Param  user_phone_number  formData   string false  "用户手机号码"
// @Param  user_job_number    formData   string false  "用户工号"
// @Param  user_gender    formData   int    false  "用户性别"
// @Success 200 {string} success
// @Failure 400 no enough input
// @Failure 500 server wrong
// @router / [post]
func (this *UserManageController) AddUser() {
    userName := this.GetString("user_name”) //获取传入参数
    //……略……
}

// @Title 删除用户
// @Description 删除用户
// @Param  user_name  body   int64  false  "用户id"
// @Success 200 {string} success
// @Failure 400 user doesn't exit
// @Failure 500 server's wrong
// @router / [delete]
func (this *UserManageController) DeleteUserById() {
   type deleteInput struct {
      Delete_id string `json:"delete_id"`
   }
   inparam := deleteInput{}
   err := json.Unmarshal(this.Ctx.Input.RequestBody, &inparam)
    //……略……
}

// @Title 修改用户信息
// @Description 修改用户信息
// @Param  user_name  formData   string false  "用户名"
// @Param  login_name formData   string false  "用户登陆名"
// @Param  user_phone_number  formData   string false  "用户手机号码"
// @Param  user_job_number    formData   string false  "用户工号"
// @Param  user_gender    formData   int    false  "用户性别"
// @Success 200 {string} success
// @Failure 400 user doesn't exit
// @Failure 500 server's wrong
// @router / [put]
func (this *UserManageController) ChangeUser() {
    changeId, _ := this.GetInt64("change_id") //获取传入参数
    //……略……
}

// @Title 获取用户列表
// @Description 获取用户列表
// @Success 200 {object} model.Users
// @Param   offset   query   string  true       "页码"
// @Param   limit query   string  true       "一页展示数量"
// @router /all [get]
func (this *UserManageController) UserManage() {
   offset, _ := this.GetInt32("offset")
   limit, _ := this.GetInt32("limit”)
    //……略……
}

  一些注释解释如下,目前的一个缺陷是@Success不能支持复杂的json返回格式,返回的object必须先定义好,比较麻烦。

注释标记 含义
@Title API 所表达的含义,是一个文本,空格之后的内容全部解析为 title
@Description API详细的描述,是一个文本,空格之后的内容全部解析为Description
@Param 参数,表示需要传递到服务器端的参数,有五列参数,使用空格或者 tab 分割。含义分别是:1.参数名
2.参数类型,可以有的值是 formData、query、path、body、header,formData 表示是 post 请求的数据,query 表示带在 url 之后的参数,path 表示请求路径上得参数,例如上面例子里面的 key,body 表示是一个 raw 数据请求,header 表示带在 header 信息中得参数。
3.参数类型
4.是否必须
5.注释
@Success 成功返回给客户端的信息,三个参数,第一个是 status code。第二个参数是返回的类型,必须使用 {} 包含,第三个是返回的对象或者字符串信息,如果是 {object} 类型,那么 bee 工具在生成 docs 的时候会扫描对应的对象,这里填写的是想对你项目的目录名和对象,例如 models.ZDTProduct.ProductList 就表示 /models/ZDTProduct 目录下的 ProductList 对象。三个参数必须通过空格分隔。
@Failure 失败返回的信息,包含两个参数,使用空格分隔,第一个表示 status code,第二个表示错误信息
@router 路由信息,包含两个参数,使用空格分隔,第一个是请求的路由地址,支持正则和自定义路由,和之前的路由规则一样,第二个参数是支持的请求方法,放在 [] 之中,如果有多个方法,那么使用 , 分隔。
  1. 配置swagger页面访问路径

  必须在route的namespace下面设置swagger路由,不然无法访问到swagger页面。

beego.SetStaticPath("/swagger", "swagger")
  1. 生成文档
命令:bee run -gendoc=true -downdoc=true

  访问地址http://localhost:8081/swagger/#! 最终可以看到文件目录中多了swagger文件夹,其中swagger.json、swagger.yaml就是beego对外提供REST API的描述,同时也自动生成系统的API的swagger网页。

三、go-micro中rpc接口的展示

  go-micro中的RPC接口使用的是Protocol Buffers协议,目前也有现成的工具可以直接根据定义的protoc文件生成html或json。那就是protoc-gen-doc,这是protocol buffers的文档生成插件,支持生成HTML、DocBook、Markdown、JSON四种类型的文档。

  1. 安装protoc-gen-doc
go get -u github.com/pseudomuto/protoc-gen-doc/cmd/protoc-gen-doc
  1. 编写protoc文件及注释

  protoc-gen-doc支持的语法很简单,目前只支持/*和//这种方式编写简单的接口说明,最终生成出来的效果不一样。可以使用/*对proto文件或定义的message进行说明,//对字段,服务方法,枚举值和扩展等说明。若某个注释不想显示,只需要加上@exclude标签即可。

syntax = "proto3";
/**
*用户模块,对外提供用户的查询管理接口
*/
service UserManage {
    //根据用户id返回用户信息
    rpc GetUserById(GetUserByIdReq) returns (UserMesssage) {}
}

message UserMesssage {
    int64 id = 1;//用户id
    string login_name = 2;//登录名
    string pwd = 3;//密码
    string name = 4;//用户名
    string phone_number = 5;//手机号码
    string job_number = 6;//工号
    int32 permission = 7;//权限
    int32 gender = 8;//性别
    bool deleted = 9;//是否删除
}

message GetUserByIdReq {
    int64 userId = 1;//用户id
}
  1. 生成html文件
      进入protoc定义文件所在目录,执行下列命令即可生成service_proto.html,包括我们系统各个服务模块定义的rpc接口的参数、作用说明。
protoc --doc_out=html,service_proto.html:./ ./*/*.proto

—doc_out可设置为html、json、markdown、docbook,最终会生成不一样的格式。目前html页面比较简单,可生成json后自己做优化展示。