传送门:https://github.com/swaggo/swag/blob/master/README_zh-CN.md
go-swagger
想要使用go-swagger
为代码自动生成接口文档,一般需要下面几个步骤:
安装swag工具
按照swagger要求给接口代码添加声明式注释,具体参照声明式注释格式。
使用swag工具扫描代码自动生成API接口文档数据
使用gin-swagger渲染在线接口文档页面
1. 安装swag工具
使用以下命令安装swag工具:
go get -u github.com/swaggo/swag/cmd/swag
swag cli
swag init -h
NAME:
swag init - Create docs.go
USAGE:
swag init [command options] [arguments...]
OPTIONS:
--generalInfo value, -g value API通用信息所在的go源文件路径,如果是相对路径则基于API解析目录 (默认: "main.go")
--dir value, -d value API解析目录 (默认: "./")
--propertyStrategy value, -p value 结构体字段命名规则,三种:snakecase,camelcase,pascalcase (默认: "camelcase")
--output value, -o value 文件(swagger.json, swagger.yaml and doc.go)输出目录 (默认: "./docs")
--parseVendor 是否解析vendor目录里的go源文件,默认不
--parseDependency 是否解析依赖目录中的go源文件,默认不
--markdownFiles value, --md value 指定API的描述信息所使用的markdown文件所在的目录
--generatedTime 是否输出时间到输出文件docs.go的顶部,默认是
2. 添加注释
添加通用的API注释
在程序入口main函数上以注释的方式写下项目相关介绍信息
package main
// @title xxx API (必填,缺少会有警告)
// @version 1.0 (必填)
// @description This is cxy api docs.
// @license.name Apache 2.0
// @contact.name go-swagger帮助文档
// @contact.url https://github.com/swaggo/swag/blob/master/README_zh-CN.md
// @host localhost:8080
// @BasePath /api/v1
// ... 其他选项看需求
func main() {
r := gin.New()
...
r.Run()
}
添加接口的注释
在你代码中处理请求的接口函数按如下方式写上注释:
// ShowAccount godoc
// @Summary Show an account
// @Description get string by ID
// @Tags accounts
// @Accept json
// @Produce json
// @Param id path int true "Account ID"
// @Success 200 {object} model.Account
// @Failure 400 {object} httputil.HTTPError
// @Failure 404 {object} httputil.HTTPError
// @Failure 500 {object} httputil.HTTPError
// @Router /accounts/{id} [get]
func (c *Controller) ShowAccount(ctx *gin.Context) {
id := ctx.Param("id")
aid, err := strconv.Atoi(id)
if err != nil {
httputil.NewError(ctx, http.StatusBadRequest, err)
return
}
account, err := model.AccountOne(aid)
if err != nil {
httputil.NewError(ctx, http.StatusNotFound, err)
return
}
ctx.JSON(http.StatusOK, account)
}
3. 生成接口文档数据
在项目根目录执行 swag init 命令,使用swag工具生成接口文档数据
报错:
2021/11/25 11:20:28 Generate swagger docs....
2021/11/25 11:20:28 Generate general API Info, search dir:./
2021/11/25 11:20:28 warning: failed to get package name in dir: ./, error: execute go list command, exit status 1, stdout:, stderr:no Go files in /home/song/appDisk/hupeng/Src/apollo
2021/11/25 11:20:28 cannot parse source files /home/song/appDisk/hupeng/Src/apollo/main.go: open /home/song/appDisk/hupeng/Src/apollo/main.go: no such file or directory
在包含main.go
文件的项目根目录运行 swag init 这将会解析注释并生成需要的文件。
执行完上述命令后,如果写的注释格式没问题,此时在包含mai.go的目录下会多出一个docs
文件夹。
./docs
├── docs.go
├── swagger.json
└── swagger.yaml
4. 引入gin-swagger渲染文档数据
然后在项目代码引入gin-swagger
相关内容:
apollo 项目的 ugc_server 的 main.go 文件
import (
"apollo/docs" // 导入swagger文档用的
gs "github.com/swaggo/gin-swagger"
"github.com/swaggo/gin-swagger/swaggerFiles"
)
在注册http路由的地方,注册swagger api相关路由
r.GET("/swagger/*any", gs.WrapHandler(swaggerFiles.Handler))
有些通用的API注释,可以动态设置
生成的代码包docs
导出SwaggerInfo
变量,使用该变量可以通过编码的方式设置,这种方式可以更灵活比如可以根据环境写不同// @host的值等等
一般都是测试环境和本地使用,生产环境禁用Swagger
这样我们可以封装一个方法来调用:
func handleSwagger(r *gin.Engine, conf *config.Configuration) {
if conf.Server.Env == config.EnvTest {
docs.SwaggerInfo.Host = conf.Server.Host + conf.Server.Addr
r.GET("/swagger/*any", gs.WrapHandler(swaggerFiles.Handler))
}
}
注:如果把 // @version, // @title 也用 SwaggerInfo
变量 来写,会有个警告。
把你的项目程序运行起来,使用该服务自己的端口,打开浏览器访问[http://ip:port/swagger/index.html#/]就能看到Swagger 2.0 Api文档了。
遇到的问题1:No operations defined in spec!
问题解决:到项目根目录下执行
swag init -g cmd/ugc_server/main.go
https://github.com/swaggo/gin-swagger/issues/99
swagger生成的接口文档页面示例
遇到的问题2:把gin库从v1.6.3升级到了v1.7.4
问题解决:
go mod edit -replace=github.com/gin-gonic/[email protected]=github.com/gin-gonic/[email protected]
遇到的问题3:ParseComment error
ParseComment error in file /home/song/appDisk/hupeng/Src/apollo/internal/handler/device/laser_cutter_list.go :cannot find type definition: common.OSLang
依赖的vendor里面的类型不识别
问题解决:
加上 --parseVendor 参数,解析vendor目录里的go源文件
swag init --parseVendor -g cmd/ugc_server/main.go
ParseComment error in file /home/song/appDisk/hupeng/Src/apollo/internal/handler/device/laser_cutter_list.go :cannot find type definition: reflect.Kind
go语言本身的类型不识别
问题解决:
加上 --parseDependency 参数
时间太久加上 --parseDepth 1 参数,依赖解析深度1减少解析时间
swag init --parseVendor --parseInternal --parseDependency --parseDepth 1 -g cmd/ugc_server/main.go
时间减少很多,每次在10秒左右,
还有一种解决方法:使用swaggertype
标签更改字段类型
ValueType reflect.Kind `json:"valueType" bson:"value_type" swaggertype:"integer"`
swag init --parseVendor -g cmd/ugc_server/main.go
时间快很多,大概在3秒左右
注解说明
@Tags: 分类信息,用逗号分割多个,写多个的话,在api文档里面会生成多个接口
@Summary: 操作的简短摘要。
@Accept json
@Produce json
@Param:参数信息,用空格分隔的参数。
param name,param type,data type,is mandatory?,comment,attribute(optional)
1.参数名,2.参数类型,3.参数数据类型,4.是否必须,5.参数描述,6.其他属性
1.参数名
参数名就是我们解释参数的名字。
2.参数类型,可以有的值是 query、path、body、header,formData
query 表示带在 url 之后的参数
path 表示请求路径上得参数
body 表示是一个 raw 数据请求,当
Accept
是JSON
格式时,我们使用该字段指定接收的JSON类型header 表示带在 header 信息中得参数
formData 表示是 post 请求的数据
3.参数数据类型
数据类型主要支持以下几种:
string (string)
integer (int, uint, uint32, uint64)
number (float32)
boolean (bool)
自定义struct
4.是否必须
5.参数描述
就是参数的一些说明,注释
6.其他属性
除了上面这些属性外,我们还可以为该参数填写一些额外的属性,如枚举,默认值,值范围等。
例如:
枚举
// @Param enumstring query string false "string enums" Enums(A, B, C)
// @Param enumint query int false "int enums" Enums(1, 2, 3)
// @Param enumnumber query number false "int enums" Enums(1.1, 1.2, 1.3)
值添加范围
// @Param string query string false "string valid" minlength(5) maxlength(10)
// @Param int query int false "int valid" mininum(1) maxinum(10)
设置默认值
// @Param default query string false "string default" default(A)
代码示例
// @Summary 分类下的模型组列表
// @Tags 模型-V3版
// @Accept json
// @Produce json
// @Param cursor body string false "游标"
// @Param limit body integer true "每页请求数"
// @Param categoryId body string true "分类id"
// @Param filterType body integer false "过滤类型"
// @Response 200 {object} httpjson.Response
// @Router /api/cxy/v3/model/listCategory [post]
func ListCategory(ctx context.Context, originReq httpjson.IRequest) (interface{}, error){
}
评:这是方式行不通,每个字段都是一个json,测试时发现请求出去的数据就使用了最后一个字段的值
curl -X 'POST' \
'http://172.29.99.145:20087/api/cxy/v3/model/listCategory' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '0'
// @Summary 分类下的模型组列表
// @Tags 模型-V3版
// @Accept json
// @Produce json
// @Param cursor formData string false "游标"
// @Param limit formData integer true "每页请求数"
// @Param categoryId formData string true "分类id"
// @Param filterType formData integer false "过滤类型"
// @Response 200 {object} httpjson.Response
// @Router /api/cxy/v3/model/listCategory [post]
func ListCategory(ctx context.Context, originReq httpjson.IRequest) (interface{}, error){
}
评:这是方式行不通,这是表单提交的格式数据
curl -X 'POST' \
'http://172.29.99.145:20087/api/cxy/v3/model/listCategory' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d 'cursor=%22%22&limit=10&categoryId=%221%22&filterType=0'
// @Summary 分类下的模型组列表
// @Tags 模型-V3版
// @Accept json
// @Produce json
// @Param req body ListCategoryReq true "req"
// @Response 200 {object} httpjson.Response
// @Router /api/cxy/v3/model/listCategory [post]
func ListCategory(ctx context.Context, originReq httpjson.IRequest) (interface{}, error){
}
评:这个可以顺利通过测试
curl -X 'POST' \
'http://172.29.99.145:20087/api/cxy/v3/model/listCategory' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"categoryId": "1",
"cursor": "",
"filterType": 0,
"limit": 10,
"reverse": false
}'
优点:
请求参数不用一个个的写了,基本上来说是一个固定格式
缺点:
1.请求参数里面body里面的数据不能指定每个字段的是否必填,只能通过注释来显示
2.返回参数不能体现真实的返回具体数据,只是一个外壳数据,解决方法如下
type ListCategoryRspData struct {
List []*model3.ModelListItem `json:"list" `
NextCursor string `json:"nextCursor" `
}
// @Summary 分类下的模型组列表
// @Tags 模型-V3版
// @Accept json
// @Produce json
// @Param req body ListCategoryReq true "req"
// @Response 200 {object} httpjson.Response{result=ListCategoryRspData}
// @Router /api/cxy/v3/model/listCategory [post]
func ListCategory(ctx context.Context, originReq httpjson.IRequest) (interface{}, error){
}
评:这个可以顺利通过测试
优点:
请求参数不用一个个的写了,基本上来说是一个固定格式
能够返回每个接口的具体数据了
缺点:
1.请求参数里面body里面的数据不能指定每个字段的是否必填,只能通过注释来显示
swagger 还有一个缺点就是前后台接口都在一个文档中,没法分文档
swagger 优点不用手动维护接口文档了
权限问题
swagger除了可以查看文档外,还可以直接try it out 调用接口,有些接口是需要登录后才能调用有个token鉴权。
校验token 的api接口 header中必须有正确的 _CXY_TOKEN 和 ** _CXY_UID** 值
可以通过添加通用的API注释来设置全局接口的header值
// @securityDefinitions.apikey cxy_token
// @name __CXY_TOKEN_
// @in header
// @securityDefinitions.apikey cxy_uid
// @name __CXY_UID_
// @in header
然后在需要登录的接口注释上增加
// @Security cxy_token
// @Security cxy_uid
这样就可以在调用接口前先设置token和uid了
安装插件 Swagger Viewer
- 在线安装
直接在vscode插件管理器中搜 Swagger Viewer 找到点击安装即可
- 离线包下载地址: https://marketplace.visualstudio.com/vscode
离线安装方法:
第一步,将扩展文件*.vsix放置在VS Code安装目录下的bin目录中,并在此目录Shift+鼠标右键,打开命令窗口
第二步:输入下面code --install ... 安装即可
C:\Users\Administrator\AppData\Local\Programs\Microsoft VS Code\bin>
code --install-extension Arjun.swagger-viewer-3.1.2.vsix