用 Swag 为 Go API 生成文档:注解实战

API 文档和代码之间的漂移是微服务项目的慢性病。接口签名改了,文档没跟上,调用方踩坑,全靠口口相传。Swag 解决这个问题的思路是:把文档写进代码注释,工具来生成 Swagger 规范文件。

代价是你必须学一套注解语法。这篇文章把最常用的部分梳理清楚,跳过官方文档里那些模糊的示例。

项目级注解

main.go 或路由初始化文件的顶部写一次,描述整个服务:

1
2
3
4
5
// @title           订单服务 API
// @version 1.0
// @description 提供订单创建、查询、取消等操作
// @host api.example.com
// @BasePath /v1

@BasePath 会作为所有路由的前缀,注意和实际注册的路由保持一致,否则 Swagger UI 里的”Try it out”会打错地址。

Handler 注解

每个接口紧贴 handler 函数上方单独注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
// CreateOrder 创建订单
//
// @Summary 创建订单
// @Description 传入商品 ID 和数量,创建一笔待支付订单
// @Tags orders
// @Accept json
// @Produce json
// @Param request body dto.CreateOrderRequest true "创建订单请求体"
// @Success 200 {object} dto.OrderResponse
// @Failure 400 {object} dto.ErrorResponse
// @Failure 500 {object} dto.ErrorResponse
// @Router /orders [post]
func (h *OrderHandler) CreateOrder(c *gin.Context) {

几个注意点:

  • @Summary 是列表视图里显示的短描述,控制在一行以内
  • @Description 才是详细说明,可以多行
  • @Tags 用于在 Swagger UI 里分组,团队内部要统一命名规范,不要一个接口写 order 一个写 orders
  • @Router 是必填的,漏了这行,Swag 不会识别这个接口

Param 注解

格式如下:

1
@Param  参数名  参数位置  数据类型  是否必填  "说明"  [扩展属性]

参数位置有五种:querypathbodyheaderformData

1
2
3
4
5
6
7
8
// 路径参数:GET /orders/{id}
// @Param id path int true "订单 ID"

// Query 参数:GET /orders?status=paid
// @Param status query string false "订单状态过滤" Enums(pending,paid,cancelled)

// 请求体:推荐引用结构体,不要用 object 内联
// @Param request body dto.CreateOrderRequest true "请求体"

body 参数几乎永远应该引用具体的结构体。写 body object true "某些字段" 这种模糊描述没有任何文档价值——Swag 会通过反射解析结构体的 json tag 和 example tag,生成带字段说明的展开文档。

结构体注解

被引用的结构体需要加 example tag,Swagger UI 才能展示示例值:

1
2
3
4
5
type CreateOrderRequest struct {
ProductID int `json:"product_id" example:"1001" binding:"required"`
Quantity int `json:"quantity" example:"2" binding:"required,min=1"`
Note string `json:"note" example:"尽快发货"`
}

如果字段有枚举值:

1
2
3
type OrderQuery struct {
Status string `json:"status" example:"paid" enums:"pending,paid,cancelled"`
}

认证注解

如果接口需要 Bearer token,在项目级声明:

1
2
3
// @securityDefinitions.apikey  BearerAuth
// @in header
// @name Authorization

接口级标注:

1
// @Security BearerAuth

这样 Swagger UI 会出现 Authorize 按钮,测试接口时不需要每次手动填 Authorization header。

常见问题

生成的文档里结构体字段为空: 检查字段首字母是否大写(Go 的可见性规则),以及是否有 json tag。小写字段对 reflect 不可见,不会出现在文档里。

接口没出现在文档里: Swag 只识别带 @Router 注解的函数,漏写就不会被扫描到。

跨包的模型找不到: Swag 默认只扫描项目根目录,跨包引用的结构体需要加 --parseDependency--parseGoList 参数:

1
swag init --parseDependency --parseInternal

属性注解写乱码: 官方文档里部分属性示例是机器翻译结果,可读性极差。正确的写法参考上面的 Enums 示例——直接写在注释末尾即可,不需要引号。

维护习惯

注解和代码在同一个文件里,改接口时顺手更新注解,是成本最低的同步方式。把”检查注解是否同步”加进 PR 模板的 checklist,基本能解决文档漂移问题。

不要寄希望于事后专门补文档——那永远排不进优先级。


用 Swag 为 Go API 生成文档:注解实战
https://www.krli.org/2018/04/09/swag注解指南/
作者
李科燃
发布于
2018年4月9日
许可协议