Swagger是基于标准的OpenAPI规范进行设计的。只要按照这套规范编写注解或通过扫描代码生成注解,就能生成统一标准的接口文档和一系列Swagger工具。

安装

在项目目录下:

  1. go get -u github.com/swaggo/swag/cmd/swag
  2. go get -u github.com/swaggo/gin-swagger
  3. go get -u github.com/swaggo/files
  4. go get -u github.com/alecthomas/template

验证是否安装成功。

  1. >swag -v
  2. swag version v1.7.0

写入注解

在安装完Swagger关联库后,就需要项目里的API接口编写注解,以便后续在生成时能够正确地运行。
比如:

注解 描述
@Summary 摘要
@Produce API可以产生的MIME类型的列表,可以将MIME简单理解为响应类型,例如JSON、XML、HTML等
@Tags 给API分组
@Param 参数格式,从左到右分别为:参数名,参数类型,数据类型,是否必填,注释
@Success 响应成功,从左到右分别为:状态码,参数类型,数据类型,注释
@Failure 响应失败,从左到右分别为:状态码,参数类型,数据类型,注释
@Router 路由,从左到右分别问:路由地址,HTTP方法

比如Tag的API:

  1. type Tag struct {
  2. }
  3. func NewTag() Tag {
  4. return Tag{}
  5. }
  6. func (t Tag) Get(ctx *gin.Context) {}
  7. // @Summary 获取多个标签
  8. // @Produce json
  9. // @Tags 标签
  10. // @Param name query string false "标签名称" maxlength(100)
  11. // @Param state query int false "状态" Enums(0, 1) default(1)
  12. // @Param page query int false "页码"
  13. // @Param page_size query int false "每页数量"
  14. // @Success 200 {object} model.TagSwagger "成功"
  15. // @Failure 400 {object} errcode.Error "请求错误"
  16. // @Failure 500 {object} errcode.Error "内部错误"
  17. // @Router /api/v1/tags [get]
  18. func (t Tag) List(ctx *gin.Context) {}
  19. // @Summary 新增标签
  20. // @Produce json
  21. // @Tags 标签
  22. // @Param name body string true "标签名称" minlength(3) maxlength(100)
  23. // @Param state body int false "状态" Enums(0, 1) default(1)
  24. // @Param created_by body string true "创建者" minlength(3) maxlength(100)
  25. // @Success 200 {object} model.Tag "成功"
  26. // @Failure 400 {object} errcode.Error "请求错误"
  27. // @Failure 500 {object} errcode.Error "内部错误"
  28. // @Router /api/v1/tags [post]
  29. func (t Tag) Create(ctx *gin.Context) {}
  30. // @Summary 更新标签
  31. // @Produce json
  32. // @Tags 标签
  33. // @Param id path int true "标签ID"
  34. // @Param name body string true "标签名称" minlength(3) maxlength(100)
  35. // @Param state body int false "状态" Enums(0, 1) default(1)
  36. // @Param modified_by body string true "修改者" minlength(3) maxlength(100)
  37. // @Success 200 {array} model.Tag "成功"
  38. // @Failure 400 {object} errcode.Error "请求错误"
  39. // @Failure 500 {object} errcode.Error "内部错误"
  40. // @Router /api/v1/tags/{id} [put]
  41. func (t Tag) Update(ctx *gin.Context) {}
  42. // @Summary 删除标签
  43. // @Produce json
  44. // @Tags 标签
  45. // @Param id path int true "标签ID"
  46. // @Success 200 {object} model.Tag "成功"
  47. // @Failure 400 {object} errcode.Error "请求错误"
  48. // @Failure 500 {object} errcode.Error "内部错误"
  49. // @Router /api/v1/tags/{id} [delete]
  50. func (t Tag) Delete(ctx *gin.Context) {}

然后配置MAIN方法

  1. // @title 博客系统
  2. // @version 1.0
  3. // @description 简单的博客系统
  4. // @termsOfService https://github.com/qiaokebaba/blog_service
  5. func main() {
  6. gin.SetMode(global.ServerSetting.RunMode)
  7. router := routers.NewRouter()
  8. s := &http.Server{
  9. Addr: ":" + global.ServerSetting.HttpPort,
  10. Handler: router,
  11. TLSConfig: nil,
  12. ReadTimeout: global.ServerSetting.ReadTimeout,
  13. ReadHeaderTimeout: 0,
  14. WriteTimeout: global.ServerSetting.WriteTimeout,
  15. IdleTimeout: 0,
  16. MaxHeaderBytes: 1 << 20,
  17. TLSNextProto: nil,
  18. ConnState: nil,
  19. ErrorLog: nil,
  20. BaseContext: nil,
  21. ConnContext: nil,
  22. }
  23. //global.Logger.Info("服务器启动成功,监听:")
  24. _ = s.ListenAndServe()
  25. }

生成swagger文件

在编写完或更新完注解后,在项目跟目录下,执行以下命令:

  1. > swag init
  2. 2021/02/03 11:43:40 Generate swagger docs....
  3. 2021/02/03 11:43:40 Generate general API Info, search dir:./
  4. 2021/02/03 11:43:41 Generating model.Tag
  5. 2021/02/03 11:43:41 Generating model.Model
  6. 2021/02/03 11:43:41 Generating errcode.Error
  7. 2021/02/03 11:43:41 create docs.go at docs\docs.go
  8. 2021/02/03 11:43:41 create swagger.json at docs\swagger.json
  9. 2021/02/03 11:43:41 create swagger.yaml at docs\swagger.yaml

可以看到在docs目录下,分别生成了docs.goswagger.jsonswagger.yaml文件。

添加访问路由

如何访问接口文件呢?直接添加一个路由即可,比如:

  1. import (
  2. _ "code.coolops.cn/blog_services/docs"
  3. v1 "code.coolops.cn/blog_services/internal/routers/api/v1"
  4. "github.com/gin-gonic/gin"
  5. swaggerFiles "github.com/swaggo/files"
  6. ginSwagger "github.com/swaggo/gin-swagger"
  7. )
  8. func NewRouter() *gin.Engine {
  9. r := gin.New()
  10. r.Use(gin.Logger())
  11. r.Use(gin.Recovery())
  12. r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
  13. article := v1.NewArticle()
  14. tag := v1.NewTag()
  15. apiv1 := r.Group("/api/v1")
  16. {
  17. apiv1.POST("/tags", tag.Create)
  18. apiv1.DELETE("/tags/:id", tag.Delete)
  19. apiv1.PUT("/tags/:id", tag.Update)
  20. apiv1.PATCH("/tags/:id/state", tag.Update)
  21. apiv1.GET("/tags", tag.Get)
  22. }
  23. return r
  24. }

查看接口文档

路由配置完成后,启动项目,即可在浏览器访问:http://127.0.0.1:8080/swagger/index.html,如下:
image.png

不定类型

在实际编写代码中,我们常常会遇到某个对象内的某个字段是interface,并且这个字段的类型是不定的,即公共结构体,比如:

  1. type Test struct{
  2. Username string
  3. Content interface{}
  4. }

对于这种方式的,就没有特别好的注解方式,官方给出的建议是就是定义一个针对 Swagger 的对象,专门用于Swagger接口文档的展示。

比如:

  1. type TagSwagger struct {
  2. List []*Tag
  3. Pager *app.Pager
  4. }

然后将注解处改为如下:

  1. // @Success 200 {object} model.TagSwagger "成功"

然后重新生成文件,只需执行以下命令

  1. swag init

最后的效果如下:
image.png