openApi

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

swagger.png

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