openApi
Go 的 Gin 框架不像 Python 的 FastAPI 那样原生支持 Swagger,需要我们手动引入相关工具。

swagger 界面大致由 3 部分组成,顶部的元信息,中间的接口定义,和底部(接口中用到的)模型定义
初始化
main.go
import (
"xxx/docs"
"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
)
// @title 哈哈平台 API
// @version 0.1
// @description 基于 Go + GORM 的博客系统后端
// @host localhost:8080
// @BasePath /api
func main() {
r := gin.Default()
// 注册openApi
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, ginSwagger.URL("/docs/doc.json")))
r.GET("/docs/doc.json", func(ctx *gin.Context) {
ctx.Writer.Header().Set("Content-Type", "application/json")
ctx.Writer.WriteHeader(200)
ctx.Writer.Write([]byte(docs.SwaggerInfo.ReadDoc()))
})
}
Swagger 元信息注释 一般放在main入口,使用swag init即可生成静态资源文档到根目录的docs中,如果你想单独放在一个文件中,比如
utils/docs-meta.go
package utils
// @title 哈哈平台 API
// @version 0.1
// @description 基于 Go + GORM 的博客系统后端
// @host localhost:8080
// @BasePath /api
// --- 模块别名定义区域start ---
// @Tag.name Base
// @Tag.description 基础模块
// @Tag.name User
// @Tag.description 用户模块
// --- 模块别名定义区域end ---
则你需要指定指定 Swagger 注释入口文件,而非默认入口main swag init -g utils/docs-meta.go
注意,生成命令建议补上 -d ./ --pd,体验更好 swag init -g utils/docs-meta.go -d ./ --pd
-g utils/docs-meta.go:指定 Swagger 元信息入口文件
-d ./:扫描当前项目目录
--pd:解析依赖包中的类型定义
然后构建项目 go build -o ./tmp/main .,最后启动它 ./tmp/main, 之后打开 http://localhost:8080/swagger/index.html 即可验证。建议最好使用air来管理go的开发模式,它能热更新还是简化启动脚本。
方法注释
除了Swagger元信息外,swagger 还有展示 model和具体接口的展示。这需要我们代码如下定义
routers/user.go
// GetUser 获取用户列表
// @Summary 获取用户列表
// @Description 获取用户列表,支持分页
// @Tags User
// @Param current query int false "当前页码 (默认1)"
// @Param size query int false "每页条数 (默认10)"
// @Success 200 {object} utils.JsonResult{data=model.PageResult[model.UserVO]}
// @Router /user [get]
func getUser(c *gin.Context) {
currentStr := c.Query("current")
sizeStr := c.Query("size")
current, _ := strconv.Atoi(currentStr)
size, _ := strconv.Atoi(sizeStr)
res, err := userService.GetList(current, size)
if err != nil {
utils.ResultFail(c, err.Error())
return
}
utils.ResultOk(c, res)
}
router.GET("/user", getUser)
模型定义
model/user.go
package model
import "time"
type UserVO struct {
// 必须大写开头!后面反引号里的才是数据库真实的列名
Id int `gorm:"column:id" json:"id"`
Name string `gorm:"column:name" json:"name"`
Age int `gorm:"column:age" json:"age"`
CreateTime time.Time `gorm:"column:create_time" json:"createTime"`
}
type User struct {
UserVO // 组合 Article 的所有字段
Password string `json:"password" gorm:"column:password"` // 扩展字段
}
其它
通用总结可以这么写:
在 Go 项目里写 Swagger 注释时,接口参数有两类常见写法。
GET 接口的参数一般来自 query string,传统写法是一个参数写一行 @Param:
// @Param date query string false "查询开始日期 YYYY-MM-DD"
// @Param days query int false "查询天数,默认 1"
// @Param keyword query string false "关键词"
如果 query 参数已经统一收敛到请求结构体里,也可以尝试用结构体统一声明:
// @Param query query model.TicketQueryRequest false "查询参数"
结构体字段通过 form tag 绑定 query 参数:
type TicketQueryRequest struct {
// 查询开始日期 YYYY-MM-DD
Date string `form:"date" json:"date" example:"2026-05-27"`
// 查询天数,默认 1
Days int `form:"days" json:"days" example:"1"`
// 关键词
Keyword string `form:"keyword" json:"keyword"`
}
这样可以减少重复维护,让接口绑定、参数定义和 Swagger 文档尽量复用同一份结构体。但 query struct 是否能完整展开,取决于 swaggo/swag 版本和生成效果。如果 Swagger UI 展示不符合预期,GET 参数还是逐个 @Param 最稳。
POST 接口通常更推荐用结构体声明 body 参数。因为 POST 请求体天然就是一个对象,Swagger 对 body struct 的支持也更稳定:
// @Param request body model.CreateTicketRequest true "创建工单参数"
对应结构体:
type CreateTicketRequest struct {
// 工单标题
Title string `json:"title" binding:"required" example:"登录失败"`
// 工单描述
Description string `json:"description" binding:"required"`
// 优先级:P0/P1/P2/P3
Priority string `json:"priority" enums:"P0,P1,P2,P3"`
}
所以实践上可以按这个原则来:
- GET query 参数少、需要精细控制文档展示时,逐个写
@Param。
- GET query 参数多,并且已经有请求结构体时,可以尝试
@Param query query XxxRequest false "查询参数"。
- POST / PUT / PATCH 的 JSON body,优先使用
@Param request body XxxRequest true "请求参数"。
- 字段中文说明写在结构体字段注释里,示例值、枚举、校验规则写在 tag 里。
- 如果 Swagger 生成效果不符合预期,再针对具体接口补充或回退到显式
@Param。