ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Gin接口文档自动化:gin-swagger让代码注释生成Swagger文档

Gin接口文档自动化:gin-swagger让代码注释生成Swagger文档 项目用 Go 写接口最烦的事情不是写 CRUD而是接口写完了文档还停在两个月前的旧设计。每次团队里前端同事拿着旧文档来问“这个字段现在还有吗”或者测试说“Postman 里这个接口返回全变了文档怎么不更新”我都想把文档工具链好好重做一次。这个问题在 Golang 生态里有一个比较成熟的答案gin-swagger。只要在 Handler 注释里把参数、响应、路由写清楚跑一条命令自动生成 API 文档Swagger UI 直接挂在 Gin 服务上联调的时候前端自己打开页面就能看能试。这篇文章我把自己从零接入 gin-swagger 的完整过程整理出来包含注解怎么写、swag init 怎么用、路由怎么挂、踩过哪些坑以及和 Postman 导入、Vue dist 合并部署相关的工程化内容。适合正在用 Gin 写接口、但文档维护还靠手动的团队参考也适合准备面试时聊 API 文档工具链的 Go 开发者。从项目里先建一个最简单的用户服务接口一边写代码一边生成文档所有示例都是可以直接复制跑起来的完整版。核心思路一句话让代码注释成为文档的唯一事实来源而不是在接口代码之外再维护一份会过期的 Markdown。1. 选型与整体设计gin-swagger 解决什么问题1.1 传统 API 文档维护方式的通病我早期做项目时接口文档的载体换过很多种Word 表格、语雀文档、ShowDoc、Postman 导出的 HTML。形式不重要重要的是写完之后就进入“腐烂期”。接口需求变了几次、字段名改过、响应结构从数组变成了分页对象真正常去更新文档的人是少数。代码里有强类型定义改动后编译期就能发现一半问题但文档是纯文本没有编译期也没有人主动检查过期是必然的。手写文档还有一个隐藏成本写文档的人必须额外描述请求参数、响应字段含义、错误码而这些信息有相当一部分已经在代码结构体里存在比如 JSON tag、字段名、数据类型甚至是字段注释。人力重复劳动意味着低效也意味着不一致。我做过一次接口统计线上 API 文档中大约有三成字段已经和真实代码对不上前端每次都要来问严重拖慢联调节奏。Postman 这类工具确实能展示真实请求也能分组整理接口但它是“事后记录”模式需要有人手动维护 collection。而且 Postman 的云端协作和权限在很多公司里都不是所有人能用的团队成员流动以后collection 归谁都说不清。实际开发中需要一个机制代码改动之后文档能够低成本同步最好是从注释里直接生成不再单独维护一套数据。1.2 swag gin-swagger 的基本工作链路gin-swagger 方案背后其实是一套开源工具链不是单个中间件。我画了很长时间才理解这里的完整链路实际上由swag命令行工具和gin-swaggerHTTP 处理器两部分组成。swag负责扫描 Go 源码中的结构化注释把注释解析成 Swagger/OpenAPI 规范的 JSON 描述文件gin-swagger是 Gin 生态里的适配层它接收这份 JSON在 Web 服务里提供一个同步 Swagger UI 的路由。听起来有点绕实际用起来很直接写代码注释然后命令行执行swag init最后启动服务打开/swagger/index.html。我经常给团队打的一个比方是接口注释就像后厨灶台旁边的菜谱便签厨师做菜时随时能看swag是主厨助理把这些便签定期誊写成正式菜单gin-swagger是把菜单摆在餐厅门口给客人看的展示架。三个角色的职责是分离的所以我们可以在不改业务代码的情况下自由调整文档展示层。这个方案最大的吸引力是复用注释。Go 代码里的函数注释本来就是给人看的加几个Summary、Param这样的结构化标记只是让注释的格式规范一点成本几乎为零。而且注释就在 Handler 函数上方代码 review 时可以同屏看到接口实现和接口文档不会出现改了实现忘了改文档的割裂感。1.3 几种主流文档方案对比不是所有项目都适合 swagger不同团队规模、不同接口维护频率选择不一样。我把自己试过的几类方案放一起做过比较这里直接列个表方便按实际情况参考方案维护方式自动化程度上手成本主要痛点Word/Markdown 文档人工维护低低容易过期没人爱写ShowDoc/语雀人工维护低低仍依赖人的责任心Postman Collection人工整理请求中中同步靠自觉无法自动生成Springfox/gin-swagger注解扫描生成高中需要学习注解语法自行开发文档系统前后端开发中高成本过高不推荐小团队从性价比角度gin-swagger 特别适合接口多、变更多、前端和测试需要即时访问最新文档的中小型团队。如果团队只有三五个稳定接口十年不改一次手工文档确实够用但只要接口数量上了两位数而且是给外部前端、App、小程序共用强烈建议早点接上生成式文档工具。2. 环境准备与依赖安装先把工具链跑通2.1 Golang 基础环境准备这一步不复杂但很多新人栽在环境和 PATH 配置上。当前 gin 项目普遍使用 Go 1.21 以上版本建议直接用新版本老版本遇到部分依赖会要求升级。Windows 11 上直接访问官方下载页面装最新稳定版安装时勾选“将 Go 安装到你的 PATH”选项完成后打开新终端执行go version确认。Linux 服务器上不需要走包管理器那一套直接下载 tar 包解压更可控wget https://go.dev/dl/go1.21.5.linux-amd64.tar.gz sudo tar -C /usr/local -xzf go1.21.5.linux-amd64.tar.gz echo export PATH\$PATH:/usr/local/go/bin ~/.bashrc source ~/.bashrc go version注意解压后需要把/usr/local/go/bin加到 PATH 里同时确认$GOPATH/bin也在 PATH 里否则下一步安装swag之后会找不到命令。运行go env GOPATH可以得到你的 GOPATH 路径一般 Unix 下是$HOME/goWindows 下是C:\Users\用户名\go。2.2 安装 swag 命令行工具swag的安装本质上是一条命令go install github.com/swaggo/swag/cmd/swaglatest这条命令会把可执行文件放到$GOPATH/bin目录下。很多新手执行完以后提示swag: command not found就是安装目录没有加入 PATH。Unix 系统下这样设置export PATH$(go env GOPATH)/bin:$PATHWindows 用户需要在系统环境变量里把%USERPROFILE%\go\bin加到 Path或者临时在当前 PowerShell 会话里执行$env:Path ;$env:USERPROFILE\go\bin安装完成之后跑swag --version能看到版本号就说明 OK。我遇到过一种情况公司服务器上 Go 版本比较老swag最新版要求 Go 1.20 以上安装完运行时会直接 panic这时候不要强行用最新版按项目 Go 版本安装对应老版本例如go install github.com/swaggo/swag/cmd/swagv1.16.2用版本号锁住更稳妥。2.3 在 Gin 项目中引入相关依赖新建一个干净的演示项目模块名就叫demomkdir gin-swagger-demo cd gin-swagger-demo go mod init demo go get -u github.com/gin-gonic/gin go get github.com/swaggo/gin-swagger go get github.com/swaggo/files这里有几个包需要理清gin-swagger是 Gin 的中间件封装files是内置的 Swagger UI 静态文件包真正做注释解析的swag是命令行工具不在运行时代码里所以不需要用go get安装它。swag生成后的代码会在项目里新增一个docs包之后要在 main 函数里用匿名导入把它注册进来这样编译时才会把文档数据打进二进制。2.4 版本组合与常见导入路径问题这部分是网上资料最容易让人迷路的地方。swaggo生态的版本演进过程中files包出现过github.com/swaggo/files和github.com/swaggo/files/v2两个导入路径gin-swagger在较新版本中也能适配不同构建。实际写代码时看到互相矛盾的示例多半是版本差异导致的。我机器上验证过的稳定组合如下gin v1.9.x gin-swagger v1.6.0 swag v1.16.3 files v1.0.0对应的导入代码一般是import ( github.com/gin-gonic/gin swaggerFiles github.com/swaggo/files ginSwagger github.com/swaggo/gin-swagger )如果在拉取依赖时碰到建议使用files/v2的报错或者在某个 fork 版本代码里看到ginSwagger.WrapHandler(swaggerFiles.Handler, ...)和ginSwagger.New(...)两种不同写法以官方 README 和当前 go.mod 里的实际版本为准。版本改动引发的函数签名变化通常都能在编译期暴露看到编译错误先别慌去查对应版本的文档而不是复制旧博客里的代码硬跑。3. 注解实战让注释变成文档的核心语法3.1 接口注释的基本结构这套方案的灵魂不是 Go 代码而是 Handler 上方那一段结构化的注释。swag会把这些注释解析成 Swagger 描述文件所以注释怎么写得规范直接决定文档质量。一个 Get 接口的完整注释长这样先放在这里后面逐行拆// GetUserList 返回用户列表 // Summary 获取用户列表 // Description 按分页条件查询用户列表支持关键字模糊搜索 // Tags 用户管理 // Accept json // Produce json // Param page query int false 页码 default(1) // Param page_size query int false 每页数量 default(20) // Success 200 {object} response.PageResult // Failure 400 {object} response.ErrorResponse // Router /api/v1/users [get] func GetUserList(c *gin.Context) { // 业务实现 }先看Summary这行它控制文档列表中显示的一行标题建议直接用一句话说明接口用途不要写太长。Description是详细描述可以写多行Swagger UI 里点开会显示完整说明。Tags决定接口在文档左侧的分组我习惯按业务模块分比如用户管理、订单管理比按 handler 文件分更容易找到。Accept和Produce分别表示接口的输入输出格式绝大多数 JSON 接口写json就行。如果接口只接收multipart/form-dataAccept要改成multipart/form-data否则文档里的示例会不准确。真正的核心是Param、Success、Failure和Router四类标签。3.2 Param 的五个常用位置query、path、header、body、formDataParam是文档里出现频率最高的标签语法是参数名、位置、类型、是否必填、说明。位置字段不同Swagger UI 里展示的形式也不同。Query 参数最常见用于 GET 请求的分页、过滤条件// Param keyword query string false 搜索关键字 // Param page query int false 页码 default(1) // Param page_size query int false 每页数量 default(20)Path 参数用于 RESTful 风格路径中的 ID。注意路径里要写占位符:idGin 路由里也是写:id这里保持一致// Param id path int true 用户ID // Router /api/v1/users/{id} [get]Header 参数用于传递Authorization这类请求头。即使后端有统一的鉴权中间件也建议在注解里体现不然前端从文档里看不到需要带 token// Param Authorization header string true 身份令牌格式为 Bearer {token}Body 参数用于 POST/PUT 请求类型用{object}标示并引用结构体Swagger UI 会直接把结构体生成可编辑的 JSON 示例// Param request body request.CreateUserRequest true 创建用户的请求体formData和file位置用于表单提交和文件上传是写上传类接口时最容易被忽略的。声明文件参数时类型固定为file// Param name formData string true 文件名 // Param file formData file true 待上传的文件3.3 Success、Failure 与响应模型Success是文档里另一个容易写错的标签。语法核心是状态码、返回类型、说明三部分其中返回类型最常见的是{object}后面接一个 Go 结构体类型引用// Success 200 {object} response.UserItem这个结构体引用会被swag解析出字段结构字段名以 JSON tag 为准。这里有一个很实用的细节结构体字段上方写一行注释Swagger UI 的 Schema 里就会显示这个字段描述。package response type UserItem struct { // 用户主键ID ID uint json:id example:1 // 用户昵称 Name string json:name example:张三 // 用户邮箱 Email string json:email example:zhangsanexample.com // 创建时间RFC3339 格式 CreatedAt string json:created_at example:2024-05-01T10:00:00Z }example标签是纯文档辅助的不会影响 JSON 序列化但能让 Swagger UI 的示例更真实。字段的类型注释如果只有数据类型没有示例展示页面会生成一堆空字符串和 0联调的时候反而不好用。建议对每个字段都补上example。错误响应的标注方式和成功响应一致我习惯把所有接口的错误响应统一成一个结构体package response type ErrorResponse struct { Code int json:code example:40000 Message string json:message example:参数错误 }然后每个有可能失败的方法都标上// Failure 400 {object} response.ErrorResponse // Failure 500 {object} response.ErrorResponse不要小看这一步文档里如果只看得到成功示例测试和前端拿到错误时还要猜返回结构。把错误响应模型固定下来前后端沟通成本会低很多。3.4 一个完整的用户接口示例把这些要素组合起来在handler/user.go里写一个创建用户的接口感受一下整体效果package handler import ( net/http github.com/gin-gonic/gin demo/request demo/response ) // CreateUser 创建用户 // Summary 创建用户 // Description 创建一个新的用户账号邮箱需唯一 // Tags 用户管理 // Accept json // Produce json // Param Authorization header string true 身份令牌格式为 Bearer {token} // Param body body request.CreateUserRequest true 创建用户的请求体 // Success 200 {object} response.UserItem // Failure 400 {object} response.ErrorResponse // Failure 500 {object} response.ErrorResponse // Router /api/v1/users [post] func CreateUser(c *gin.Context) { var req request.CreateUserRequest if err : c.ShouldBindJSON(req); err ! nil { c.JSON(http.StatusBadRequest, response.ErrorResponse{ Code: 40000, Message: err.Error(), }) return } // 这里省略实际落库逻辑 c.JSON(http.StatusOK, response.UserItem{ ID: 1, Name: req.Name, Email: req.Email, }) }对应的请求结构体单独放到request/user.go注释同样要写清楚package request type CreateUserRequest struct { // 用户昵称1 到 32 个字符 Name string json:name binding:required // 用户邮箱需要符合邮箱格式 Email string json:email binding:required,email }写完这些代码后接口注释和结构体都在同一批文件里代码和文档之间没有空间距离实时性就有了基础保障。4. swag init 生成与 router 挂载4.1 main 函数顶部的全局信息注解Param和Success只能描述单个接口Swagger 页面顶部显示的整份文档标题、版本号、服务地址需要单独的全局注解。它们不是写在某个 Handler 上而是写在main.go最顶部package main // title 用户服务 API // version 1.0.0 // description 这是用户服务接口文档包含用户模块的完整能力。 // termsOfService http://swagger.io/terms/ // contact.name API Support // contact.email supportexample.com // host localhost:8080 // BasePath /api/v1 // securityDefinitions.apikey ApiKeyAuth // in header // name Authorization func main() { // ... }host是文档里 Try it out 功能默认请求的地址。如果本地跑服务端口一般是 8080 就直接写localhost:8080如果服务由 Nginx 反代到域名下这里写成公网域名。注意协议本身不用写在 host 里文档里默认按服务访问协议推断有特殊要求还可以加Schemes https这类配置不过日常项目用不上这么细。securityDefinitions.apikey这段不是给所有接口强制加鉴权的它只是声明这套 API 存在一种叫ApiKeyAuth的鉴权方式。要让某个接口显示“需要鉴权”在那个 Handler 注释里增加一行Security ApiKeyAuth。这是一个很容易漏掉的点很多人配完了全局接口文档里还是看不到鉴权按钮就是因为单个方法上没声明。4.2 执行 swag init 并理解 docs 目录整个项目代码完成后在项目根目录执行swag init默认情况下swag会扫描当前目录下所有 Go 文件解析带结构注释的代码并在docs目录下生成三个文件docs.go、swagger.json、swagger.yaml。我自己在真实项目中会用更精确的参数避免把无关代码也扫描进去swag init -g main.go -o docs --parseDependency --parseInternal-g main.go指定从 main 文件开始扫描-o docs指定输出目录。用--parseDependency可以让swag进入依赖包去解析引用的结构体否则某些引用了 external 包结构体的注解会解析不出来。这个参数不是默认开启的遇到swag报错说找不到某个类型时加上它试一下。生成完成后docs目录要提交进 Git。我在代码评审里见过有人建议不提交 docs部署时再执行生成但这样会引入两个问题一是部署环境必须安装 Go 工具链和swag二是如果两个分支改的接口不同生成的 swagger.json 可能会出现内容冲突却无法在 MR 中直接审查。提交 docs 虽然会在每次接口变更时产生一次生成文件的 diff但这是让文档可追溯、可 review 的最低成本方式。4.3 挂载 Swagger 路由docs生成以后main.go 里需要引包并注册路由。这里有一个非常容易踩的坑docs 包名是docs但它的引用路径要带项目模块名前缀。package main import ( net/http github.com/gin-gonic/gin swaggerFiles github.com/swaggo/files ginSwagger github.com/swaggo/gin-swagger _ demo/docs ) // title 用户服务 API // version 1.0.0 // host localhost:8080 // BasePath /api/v1 func main() { r : gin.Default() // 业务路由 api : r.Group(/api/v1) api.GET(/users, func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{list: []string{a, b}}) }) // Swagger 路由 r.GET(/swagger/*any, ginSwagger.WrapHandler(swaggerFiles.Handler)) r.Run(:8080) }关键是路由必须注册为/swagger/*any网上很多老博客写的/swagger/:param是不能用的。*any是 Gin 的 wildcard 语法能匹配/swagger/index.html、/swagger/doc.json等路径。启动服务以后在浏览器访问http://localhost:8080/swagger/index.html如果看到 Swagger UI 页面并且左侧能看到Users管理分组的接口说明整条链路已经通了。页面上方有一个 Try it out 按钮点开以后可以直接输入参数向真实服务发起请求联调阶段非常方便。4.4 修改注解后的标准操作流程接入这套工具后团队需要注意一个工作流变化每次改动接口签名、请求体、响应体都要重新执行swag init然后重启服务。我习惯把操作刻意固定成标准三步改代码、跑命令、刷新页面看效果。swag init go run main.go如果项目在用 air 这类热重载工具重新执行swag init已经改变了docs目录下 Go 文件的内容热重载工具会发现变化并自动重新编译。没有热重载的话每次改了接口注释必须重启不然页面里看到的还是旧文档。忘记swag init是最常见的“文档没更新”原因而且这种问题没有任何报错提示排查思路基本就是先看swagger.json内容确定生成时间对不对。5. 常见问题与排查技巧实录5.1 高频问题速查表这里把我的踩坑记录整理成表格遇到的绝大多数问题都能在里面找到答案现象常见原因解决方案swag 命令找不到GOPATH/bin 没加入 PATH执行go env GOPATH并把对应 bin 目录加入 PATHswag init 报类型找不到未开启依赖解析命令加--parseDependency --parseInternal/swagger/index.html404路由注册写错确认路由是/swagger/*any而不是/:param页面打开了但接口为空docs 未刷新或注解格式错误看 swagger.json 内容打开 swag init 输出日志结构体字段全是空描述结构体字段上方没写注释在字段上补// 字段说明鉴权按钮未出现缺少单接口 Security 注解Handler 注释加Security ApiKeyAuthdocs.go 冲突多人同时跑 swag init重新生成解决 Git 冲突时保留正确 JSON文档地址被外部访问未做访问控制使用授权中间件或按环境关闭 Swagger 路由页面样式丢失files 包版本不匹配检查 gin-swagger 与 files 版本组合5.2 例子swagger.json 内容和页面不一致我遇到过几次很让人困惑的情况接口页面里能看到新接口但参数说明还是旧的前端同事把旧参数发过来后端报字段不存在。这类问题一般不是单个注解写错而是swag init成功执行了但解析的源文件不是我以为的那个。对比一下docs/swagger.json里paths字段下的实际内容能看到接口路径是否与当前代码一致。另外一个排查思路是在项目里搜索旧的接口路径或字段名如果还有残留说明项目里有历史版本代码swag init扫描到了旧目录。对于多目录项目建议始终用-g main.go指定入口。我就在一个模块下同时存在新旧两套 Handler 时踩过这种坑后来干脆把命令固定成脚本每次执行都先删除docs目录再重新生成以此保证文档是全新编译出来的。rm -rf docs swag init -g main.go -o docs --parseDependency这个命令可以在项目根目录直接执行也可以加进 Makefile 里的make docs避免团队成员每个人敲的参数不一样生成的 docs 文件风格各不相同。5.3 示例Body 参数不被识别还有一个典型问题是 POST 接口的 body 参数总不被识别页面里只显示成功响应请求 Body 区域空白。原因通常是 Handler 注释里把 body 参数类型写成字符串而不是{object}正确的做法是// Param body body request.CreateUserRequest true 创建用户的请求体request.CreateUserRequest是项目内的结构体类型swag需要能够从代码里找到它。如果这个结构体定义在另一个包且没有开依赖解析就会出现找不到该类型的问题。另一个细节是结构体必须是可导出类型字段也要大写开头即使后端字段自己知道 JSON tag 是小写类型定义里也不能写成小写字段否则反射解析不到。6. 进阶玩法与团队协作链路打通6.1 把 Swagger 文档导入 PostmanSwagger 文档可以导入 Postman前端和测试同事不一定要打开 Swagger UI也可以继续用自己熟悉的 Postman。我这里给了两个导入路径。不用先导出文件直接给 Postman 一个地址就行。Swagger UI 打开时能看到 service worker 发请求它请求的底层 JSON 地址是http://localhost:8080/swagger/doc.json。打开 Postman 的 Import 功能选择 Link 粘贴这个地址Postman 会拉取 JSON 并解析成 Collection。本地 Swagger 服务没起的时候直接用本机 JSON 文件也可以。进到 Swagger UI 页面后从http://localhost:8080/swagger/doc.json页面右键另存到本地在 Postman Import 里选 Upload File。导入之前记得确认格式swag默认生成的是 Swagger 2.0Postman 能正常导入个别字段的默认值、示例值可能丢但不影响调试。导入完成后的 Collection 会按Tags自动分组比如“用户管理”“订单管理”。需要注意一点如果接口需要在 Header 里传 token导入以后 Postman 不会自动帮你保存这个头需要在 Collection 级别建一个变量例如{{token}}然后在 Authorization 配置里引用。这个坑我在团队里反复提过否则每次导入新版本又要重新处理。6.2 gin 集成 vue dist 合并部署时如何处理 swagger最近很多人提到把 Vue 打包后的 dist 文件用 gin 的静态资源服务托管实现前后端单端口部署。这种模式同时也要考虑 swagger 怎么不冲突。Vue dist 一般通过StaticFS或者embed的方式托管例如package main import ( embed io/fs net/http github.com/gin-gonic/gin swaggerFiles github.com/swaggo/files ginSwagger github.com/swaggo/gin-swagger demo/docs ) //go:embed dist var distFS embed.FS func main() { r : gin.Default() // Swagger 路由 r.GET(/swagger/*any, ginSwagger.WrapHandler(swaggerFiles.Handler)) // Vue 静态资源路由 dist, _ : fs.Sub(distFS, dist) r.StaticFS(/, http.FS(dist)) r.Run(:8080) }这里有个路由冲突的隐患如果 Vue dist 里面有index.html而 Gin 的StaticFS(/)同时托管swagger路径被StaticFS拦截的可能性极大。实践上必须把 Swagger 路由注册放在通用静态路由之前否则/swagger/index.html会被 Vue 的 fallback 处理掉。更好的做法是把 Vue 静态资源挂在子路径下比如r.StaticFS(/web, http.FS(dist))只在 Nginx 层把根路径代理过来。还有 Vue router 开启 history 模式时直接访问/users刷新页面会出现 404这个问题的处理方式和 swagger 无关但两种能力混在一起容易把人搞懵。遇到静态资源被吞、接口 404、页面白屏这类问题建议先把 Swagger 路由从代码里临时注释掉做二分定位。6.3 生产环境的文档安全控制策略Swagger UI 很方便也意味着它暴露了接口全貌生产环境不能裸奔。我的默认策略是区分环境开发环境和测试环境直接开启生产环境用环境变量控制。func main() { r : gin.Default() // 只有显式开启时才注册 Swagger 路由 if os.Getenv(ENABLE_SWAGGER) true { r.GET(/swagger/*any, ginSwagger.WrapHandler(swaggerFiles.Handler)) } }如果生产环境确实还要留一个入口可以用 Basic Auth 包一层。Gin 路由分组天然支持swaggerGroup : r.Group(/swagger, gin.BasicAuth(gin.Accounts{ admin: your-password, })) swaggerGroup.GET(/*any, ginSwagger.WrapHandler(swaggerFiles.Handler))这样即使路由暴露外部也无法直接访问页面至少挡掉绝大多数的自动扫描。注意 Basic Auth 密码在 Go 源码里是明文注意权限控制更严格的做法是接公司统一鉴权中间件或者放到内网网关后面。6.4 团队协作中注解的约定与代码评审工具接入以后还要配套团队约定才能发挥效果。我在团队里立过三条不成文的规矩新增或修改接口必须同步修改注解接口评审时同时看 Handler 代码和注释swagger.json 的变化要放进 MR 的 diff 里reviewer 不该跳过这些生成文件直接只看业务代码字段结构体注释要写清楚单位、范围、格式不能只写“时间”两个字。写注解时也会有些常见的坏味道。比如描述过于简短像“用户接口”等于没写Description写着“这是一个创建订单的接口”却没有写清订单创建成功的返回结构。反过来冗余信息太多也会让注解变得很沉像把整个业务流程写进 description。拿捏多少合适可以看联调时前端真正需要的字段参数名、是否必填、默认值、响应结构、错误结构把这些给全就够了。Swagger 最终只是把注释转换成渲染页面如果注释本身质量不高生成出来的文档依然是垃圾。工具解决了“同步”问题没有解决“表达”问题注释质量要靠团队规范约束。接入 gin-swagger 这件事本身不难真正有价值的是把“写接口”和“写文档”这两件本来分离的事情拉到同一份代码里。以前我总担心接口文档过期现在团队里的接口注释就是接口文档postman 导入、前后端对接、测试用例编写都从 swagger.json 出发改造接口后文档自动跟着代码走。如果你也处在接口多次变更、文档反复过期、前端反复来问的节奏里把 gin-swagger 接进项目是值得投入的一个优化方向。我自己后续还会在这个基础上做接口契约测试把 swagger.json 当基准对比实际返回的真实数据那又是一套新的玩法了。
返回列表