English | 中文
⚡️ 一个美观、强大的 Swagger UI 替代方案,支持 Gin、Fiber、Echo、Chi 等主流 Go Web 框架。
为 Go 开发者提供更好的 API 文档体验。
- 🌐 在线预览: https://wdc.zeabur.app/swagger/
- 📖 完整文档: https://wdc.zeabur.app/qingfeng/qingfeng.html
- 🚀 快速开始: https://wdc.zeabur.app/qingfeng/01-quick-start.html
- 🔌 多框架支持: https://wdc.zeabur.app/qingfeng/06-frameworks.html
https://wdc.zeabur.app/swagger/
- 🚀 内置文档生成器 - 无需安装 swag CLI,零外部依赖
- 📄 OpenAPI 3.0/3.1 支持 - 自动生成现代化的 OpenAPI 3.x 规范文档
- ⚡ 一行代码启用 - 只需设置
AutoGenerate: true,文档自动生成 - 🔄 完全向后兼容 - 现有用户无需修改任何代码
- 🎨 多主题支持 - 提供 Default、Minimal、Modern 三种 UI 风格
- 🌓 深色/浅色模式 - 支持主题切换,保护眼睛
- 🎯 多种主题色 - 蓝、绿、紫、橙、红、青六种主题色可选
- 🔍 快速搜索 - 实时搜索接口,快速定位(支持 Ctrl+K 快捷键)
- 🐛 在线调试 - 内置 API 调试工具,类似 Postman
- 🔑 全局请求头 - 支持配置全局 Headers(如 Authorization)
- 🪄 Token 自动提取 - 从响应中自动提取 Token 设置到全局参数
- 🔄 内置文档生成 - 无需安装 swag,启动时自动生成 OpenAPI 3.0 文档
- 📦 零依赖前端 - 使用 embed.FS 内嵌,无需额外部署
- 🚀 简单集成 - 一行代码接入现有项目
- 📱 移动端适配 - 完美支持手机访问,侧边栏抽屉式交互
- 💾 设置持久化 - 主题、UI 风格、全局参数自动保存到本地
- ✨ JSON 语法高亮 - 响应结果彩色高亮显示
- 🔌 多框架支持 - 原生支持 Gin,其他框架可通过标准 http.Handler 适配
v2.0.0 新增:内置文档生成器,无需安装任何外部工具!
package main
import (
"github.com/gin-gonic/gin"
qingfeng "github.com/wdcbot/qingfeng"
)
// @title 我的 API
// @version 1.0
// @description 这是我的 API
// @host localhost:8080
// @BasePath /api
func main() {
r := gin.Default()
// 一行代码启用文档 - 自动生成 OpenAPI 3.0
r.GET("/doc/*any", qingfeng.Handler(qingfeng.Config{
Title: "我的 API",
AutoGenerate: true, // 内置生成器,无需安装 swag CLI
}))
// API 路由
r.GET("/api/hello", hello)
r.Run(":8080")
}
// @Summary 打招呼
// @Tags 示例
// @Success 200 {string} string "Hello World"
// @Router /hello [get]
func hello(c *gin.Context) {
c.JSON(200, gin.H{"message": "Hello World"})
}就这么简单! 用户只需要:
go get github.com/wdcbot/qingfeng@latest- 写注释
- 启动服务
无需安装 swag CLI,无需运行 swag init,文档自动生成!
如果你的项目已经在使用其他 Swagger UI 组件(如 gin-swagger、swaggo 等),可以无侵入替换为青峰Swag:
只需两步:
- 安装青峰Swag:
go get github.com/wdcbot/qingfeng@latest
# 国内镜像: go get gitee.com/xiaowan1997/qingfeng- 替换路由注册(保留原有的 swag 注释和 docs 目录):
// 替换前 (gin-swagger)
import swaggerFiles "github.com/swaggo/files"
import ginSwagger "github.com/swaggo/gin-swagger"
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
// 替换后 (青峰Swag) - 方式1:使用内置生成器(推荐)
import qingfeng "github.com/wdcbot/qingfeng"
r.GET("/doc/*any", qingfeng.Handler(qingfeng.Config{
Title: "我的 API",
AutoGenerate: true, // 内置生成器,无需 swag CLI
}))
// 替换后 (青峰Swag) - 方式2:使用已有的 swagger.json
r.GET("/doc/*any", qingfeng.Handler(qingfeng.Config{
DocPath: "./docs/swagger.json", // 兼容 Swagger 2.0 和 OpenAPI 3.0
}))无需修改:
- ✅ 原有的 swag 注释(@Summary、@Router 等)
- ✅ 已生成的 docs 目录(swagger.json、swagger.yaml)
- ✅ 业务代码
mkdir myapi && cd myapi
go mod init myapigo get github.com/gin-gonic/gin
go get github.com/wdcbot/qingfeng@latest
# 国内镜像: go get gitee.com/xiaowan1997/qingfeng@latest
# 注意:v2.0.0 起无需安装 swag CLI!package main
import (
"github.com/gin-gonic/gin"
qingfeng "github.com/wdcbot/qingfeng"
)
// @title 我的 API
// @version 1.0
// @description 这是我的第一个 API
// @host localhost:8080
// @BasePath /api
func main() {
r := gin.Default()
// 注册文档 UI(内置生成器,无需 swag CLI)
r.GET("/doc/*any", qingfeng.Handler(qingfeng.Config{
Title: "我的 API",
AutoGenerate: true, // 启用内置生成器
}))
// API 路由
r.GET("/api/hello", hello)
r.Run(":8080")
}
// @Summary 打招呼
// @Tags 示例
// @Success 200 {string} string "Hello World"
// @Router /hello [get]
func hello(c *gin.Context) {
c.JSON(200, gin.H{"message": "Hello World"})
}r.GET("/doc/*any", qingfeng.Handler(qingfeng.Config{
// 文档标题
Title: "我的 API",
// 文档描述
Description: "API 文档描述",
// API 版本号
Version: "1.0.0",
// 文档路由前缀
BasePath: "/doc",
// ===== 文档来源(三选一)=====
// 方式1:启用内置生成器(推荐,无需安装 swag CLI)
AutoGenerate: true,
// 方式2:指定文档文件路径(支持 Swagger 2.0 和 OpenAPI 3.0)
// DocPath: "./docs/swagger.json",
// 方式3:直接传入文档 JSON 内容
// DocJSON: []byte{},
// ===== UI 配置 =====
// 是否启用在线调试
EnableDebug: true,
// 是否默认深色模式
DarkMode: false,
// UI 主题风格: ThemeDefault(默认) / ThemeMinimal(简约) / ThemeModern(现代)
UITheme: qingfeng.ThemeModern,
// ===== 高级配置 =====
// 全局请求头配置
GlobalHeaders: []qingfeng.Header{
{Key: "Authorization", Value: "Bearer your-token"},
},
// 自定义 Logo
Logo: "https://example.com/logo.png",
LogoLink: "https://example.com",
// 多环境配置
Environments: []qingfeng.Environment{
{Name: "本地开发", BaseURL: "/api/v1"},
{Name: "测试环境", BaseURL: "https://test-api.example.com/api/v1"},
{Name: "生产环境", BaseURL: "https://api.example.com/api/v1"},
},
// ===== 生成器配置(AutoGenerate: true 时生效)=====
// 搜索目录
SwagSearchDir: ".",
// 输出目录
SwagOutputDir: "./docs",
}))go run main.go
# 无需运行 swag init!文档自动生成打开浏览器访问:http://localhost:8080/doc/
package main
import (
"github.com/gin-gonic/gin"
qingfeng "github.com/wdcbot/qingfeng"
)
func main() {
r := gin.Default()
// 注册青峰Swag文档 UI
r.GET("/doc/*any", qingfeng.Handler(qingfeng.Config{
Title: "我的 API",
AutoGenerate: true, // 内置生成器
}))
r.Run(":8080")
}访问 http://localhost:8080/doc/ 查看文档。
青峰Swag 通过 HTTPHandler 返回标准的 http.Handler,支持所有 Go Web 框架:
package main
import (
"net/http"
qingfeng "github.com/wdcbot/qingfeng"
)
func main() {
// 使用 HTTPHandler 返回标准 http.Handler
http.Handle("/doc/", qingfeng.HTTPHandler(qingfeng.Config{
Title: "My API",
BasePath: "/doc",
AutoGenerate: true,
}))
http.HandleFunc("/api/hello", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`{"message": "Hello World"}`))
})
http.ListenAndServe(":8080", nil)
}package main
import (
"github.com/labstack/echo/v4"
qingfeng "github.com/wdcbot/qingfeng"
)
func main() {
e := echo.New()
// Echo 使用 WrapHandler 包装
e.GET("/doc/*", echo.WrapHandler(qingfeng.HTTPHandler(qingfeng.Config{
Title: "My API",
BasePath: "/doc",
AutoGenerate: true,
})))
e.GET("/api/hello", func(c echo.Context) error {
return c.JSON(200, map[string]string{"message": "Hello World"})
})
e.Start(":8080")
}package main
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/adaptor"
qingfeng "github.com/wdcbot/qingfeng"
)
func main() {
app := fiber.New()
// Fiber 使用 adaptor.HTTPHandler 包装
app.Use("/doc", adaptor.HTTPHandler(qingfeng.HTTPHandler(qingfeng.Config{
Title: "My API",
BasePath: "/doc",
AutoGenerate: true,
})))
app.Get("/api/hello", func(c *fiber.Ctx) error {
return c.JSON(fiber.Map{"message": "Hello World"})
})
app.Listen(":8080")
}package main
import (
"net/http"
"github.com/go-chi/chi/v5"
qingfeng "github.com/wdcbot/qingfeng"
)
func main() {
r := chi.NewRouter()
// Chi 直接使用 Handle
r.Handle("/doc/*", qingfeng.HTTPHandler(qingfeng.Config{
Title: "My API",
BasePath: "/doc",
AutoGenerate: true,
}))
r.Get("/api/hello", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`{"message": "Hello World"}`))
})
http.ListenAndServe(":8080", r)
}package main
import (
"github.com/gin-gonic/gin"
qingfeng "github.com/wdcbot/qingfeng"
)
func main() {
r := gin.Default()
// Gin 可以直接使用 Handler(内部调用 HTTPHandler)
r.GET("/doc/*any", qingfeng.Handler(qingfeng.Config{
Title: "My API",
AutoGenerate: true,
}))
r.Run(":8080")
}💡 核心原理:
qingfeng.HTTPHandler()返回标准的http.Handler接口,任何支持标准库的框架都可以使用。
支持三种 UI 风格,可通过 UITheme 配置或在界面中切换:
| 主题 | 常量 | 说明 |
|---|---|---|
| Default | qingfeng.ThemeDefault |
经典蓝色风格,功能完整 |
| Minimal | qingfeng.ThemeMinimal |
黑白极简,专业干净 |
| Modern | qingfeng.ThemeModern |
渐变毛玻璃,视觉冲击 |
也可以通过 URL 参数切换主题:http://localhost:8080/doc/?theme=modern
切换后的主题会自动保存到浏览器本地存储,下次访问自动恢复。
青峰Swag 完美适配移动端:
- 📲 抽屉式侧边栏 - 点击左上角菜单按钮打开接口列表
- 🎯 顶部操作栏 - Headers、Token、主题等功能一键访问
- 💾 设置同步 - 主题和参数设置在移动端和桌面端同步
- 🌓 深色模式 - 右上角一键切换,保护眼睛
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| Title | string | "API Documentation" | 文档标题 |
| Description | string | "" | 文档描述 |
| Version | string | "1.0.0" | API 版本 |
| BasePath | string | "/doc" | 文档路由前缀 |
| AutoGenerate | bool | false | 启用内置生成器(推荐,无需 swag CLI) |
| DocPath | string | "" | 文档文件路径(支持 Swagger 2.0 和 OpenAPI 3.0) |
| DocJSON | []byte | nil | 直接传入文档 JSON 内容 |
| EnableDebug | bool | true | 是否启用在线调试 |
| DarkMode | bool | false | 是否默认深色模式 |
| UITheme | UITheme | ThemeDefault | UI 主题风格 |
| GlobalHeaders | []Header | nil | 全局请求头配置 |
| SwagSearchDir | string | "." | 搜索目录(AutoGenerate 时生效) |
| SwagOutputDir | string | "./docs" | 输出目录(AutoGenerate 时生效) |
| Logo | string | "" | 自定义 Logo URL 或 base64 |
| LogoLink | string | "" | Logo 点击跳转链接 |
| Environments | []Environment | nil | 多环境配置 |
💡 文档来源优先级:
DocJSON>DocPath>AutoGenerate
使用 go:embed 将 swagger.json 嵌入二进制文件,无需单独 COPY docs 目录:
package main
import (
_"embed""embed"
"github.com/gin-gonic/gin"
qingfeng "github.com/wdcbot/qingfeng"
)
//go:embed docs/swagger.json
var swaggerJSON []byte
func main() {
r := gin.Default()
r.GET("/doc/*any", qingfeng.Handler(qingfeng.Config{
Title: "我的 API",
BasePath: "/doc",
DocJSON: swaggerJSON, // 直接嵌入,无需 DocPath
}))
r.Run(":8080")
}这样 Dockerfile 只需要:
FROM golang:1.20-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o main .
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/main .
# 不需要 COPY docs 目录!
EXPOSE 8080
CMD ["./main"]支持配置多个环境,方便在开发、测试、生产环境间切换:
r.GET("/doc/*any", qingfeng.Handler(qingfeng.Config{
Title: "我的 API",
BasePath: "/doc",
DocPath: "./docs/swagger.json",
Environments: []qingfeng.Environment{
{Name: "本地开发", BaseURL: "http://localhost:8080/api/v1"},
{Name: "测试环境", BaseURL: "https://test-api.example.com/api/v1"},
{Name: "生产环境", BaseURL: "https://api.example.com/api/v1"},
},
}))支持配置自定义 Logo:
r.GET("/doc/*any", qingfeng.Handler(qingfeng.Config{
Title: "我的 API",
BasePath: "/doc",
DocPath: "./docs/swagger.json",
Logo: "https://example.com/logo.png", // 或 base64
LogoLink: "https://example.com", // 点击跳转
}))在调试面板中,可以将常用的请求体保存为模板:
- 在请求体输入框上方点击「保存模板」
- 输入模板名称
- 下次使用时点击「模板」按钮选择已保存的模板
模板按接口保存,每个接口可以有多个模板。
| 快捷键 | 功能 |
|---|---|
Ctrl/Cmd + K |
聚焦搜索框 |
Escape |
关闭弹窗 |
可以预设全局请求头,会自动添加到所有 API 请求中:
r.GET("/doc/*any", qingfeng.Handler(qingfeng.Config{
Title: "我的 API",
BasePath: "/doc",
DocPath: "./docs/swagger.json",
GlobalHeaders: []qingfeng.Header{
{Key: "Authorization", Value: "Bearer your-token"},
{Key: "X-API-Key", Value: "your-api-key"},
},
}))也可以在界面中通过「全局参数」按钮动态配置。
启用 AutoGenerate 后,每次启动服务会自动运行 swag init:
r.GET("/doc/*any", qingfeng.Handler(qingfeng.Config{
Title: "我的 API",
BasePath: "/doc",
AutoGenerate: true, // 启用自动生成
SwagSearchDir: ".", // swag 搜索目录
SwagOutputDir: "./docs", // 输出目录
}))需要先安装 swag:
go install github.com/swaggo/swag/cmd/swag@latest- 安装 swag:
go install github.com/swaggo/swag/cmd/swag@latest- 在代码中添加注释:
// @Summary 获取用户列表
// @Description 分页获取用户
// @Tags 用户管理
// @Accept json
// @Produce json
// @Param page query int false "页码"
// @Success 200 {object} Response
// @Router /users [get]
func getUsers(c *gin.Context) {
// ...
}- 生成文档:
swag init- 集成青峰Swag (见快速开始)
欢迎提交 Issue 和 Pull Request!
除了 Gin,青峰Swag 还提供标准 http.Handler,可适配任何 Go Web 框架:
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/adaptor"
qingfeng "github.com/wdcbot/qingfeng"
)
func main() {
app := fiber.New()
app.Use("/doc", adaptor.HTTPHandler(qingfeng.HTTPHandler(qingfeng.Config{
Title: "我的 API",
BasePath: "/doc",
DocPath: "./docs/swagger.json",
})))
app.Listen(":8080")
}import (
"github.com/labstack/echo/v4"
qingfeng "github.com/wdcbot/qingfeng"
)
func main() {
e := echo.New()
e.GET("/doc/*", echo.WrapHandler(qingfeng.HTTPHandler(qingfeng.Config{
Title: "我的 API",
BasePath: "/doc",
DocPath: "./docs/swagger.json",
})))
e.Start(":8080")
}import (
"github.com/go-chi/chi/v5"
qingfeng "github.com/wdcbot/qingfeng"
)
func main() {
r := chi.NewRouter()
r.Handle("/doc/*", qingfeng.HTTPHandler(qingfeng.Config{
Title: "我的 API",
BasePath: "/doc",
DocPath: "./docs/swagger.json",
}))
http.ListenAndServe(":8080", r)
}import (
"net/http"
qingfeng "github.com/wdcbot/qingfeng"
)
func main() {
http.Handle("/doc/", qingfeng.HTTPHandler(qingfeng.Config{
Title: "我的 API",
BasePath: "/doc",
DocPath: "./docs/swagger.json",
}))
http.ListenAndServe(":8080", nil)
}扫码添加微信,备注「青峰」加入交流群:
MIT License
