swaggo/swag 提供了Go版本的Swagger自动生产RESTful API文档,其做法是在代码中按Swaggo的格式编写API注释,然后Swaggo会去解析这些注释,生成Swagger的文档以及托管到Web的框架代码,最终将代码编译到Web应用中,达到API文档托管的目的。
go-swagger是一套完整且功能齐全的高性能API组件,可与Swagger-API一起使用,分为三块分别是服务端、客户端、数据模型。
swagger
Swagger优势
- 支持API自动生成同步的在线文档,使用Swagger后可直接通过代码生成文档,无需手动编写接口文档。
- 提供Web页面的在线测试API,仅需定义好参数和格式,直接在界面上输入参数对应的值即可在线测试接口。
swaggo
- swag命令可以将Go的注释转换为Swagger文档
- swaggo支持的Web框架包括gin、echo、buffalo、net/http。
swaggo使用前需安装swag脚手架命令行工具、HTTP服务器、模板
$ go get -u -v github.com/swaggo/swag/cmd/swag
$ go get -u -v github.com/swaggo/http-swagger
$ go get -u -v github.com/alecthomas/template
-
swag
库将Go批注转换为Swagger文档,随后由http-swagger使用,为SwaggerUI提供服务。 -
http-swagger
库使用swag
生成的文档帮助提供SwaggerUI -
template
库用于安装模板,这是Go的text/template
包的分支,swag
生成的docs.go
文件中需此依赖关系,而在没有该依赖关系的情况下运行应用程序时会得到一个错误。
swag
- 文档地址 https://gitcode.net/mirrors/swaggo/swag/-/blob/master/README_zh-CN.md
安装Swag命令行
使用Swaggo首先要下载一个Swag命令行(脚手架)
$ go get -u -v github.com/swaggo/swag/cmd/swag
安装成功后会在GOPATH
下的bin
文件夹内生成swag.exe
命令行工具
$ swag --version
swag version v1.7.8
安装最新版本
$ go install -v github.com/swaggo/swag/cmd/swag@latest
$ swag -v
swag version v1.7.8
在包含main.go
主入口的工程根目录下执行swag init
初始化,swag
会检索当前工程中的swag注释。
$ cd gwf
$ swag init
执行swag init
命令后会在项目根目录下生成docs
文件夹,同时文件夹下会生成三个文件docs.go
、swagger.json
、swagger.yaml
。
查看swag
命令支持的选项
$ swag --help
NAME:
swag - Automatically generate RESTful API documentation with Swagger 2.0 for Go.
USAGE:
swag [global options] command [command options] [arguments...]
VERSION:
v1.7.8
COMMANDS:
init, i Create docs.go
fmt, f format swag comments
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--help, -h show help (default: false)
--version, -v print the version (default: false)
swag init
$ swag init --help
NAME:
swag init - Create docs.go
USAGE:
swag init [command options] [arguments...]
OPTIONS:
--generalInfo value, -g value Go file path in which 'swagger general API Info' is written (default: "main.go")
--dir value, -d value Directories you want to parse,comma separated and general-info file must be in the first one (default: "./")
--exclude value Exclude directories and files when searching, comma separated
--propertyStrategy value, -p value Property Naming Strategy like snakecase,camelcase,pascalcase (default: "camelcase")
--output value, -o value Output directory for all the generated files(swagger.json, swagger.yaml and doc.go) (default: "./docs")
--parseVendor Parse go files in 'vendor' folder, disabled by default (default: false)
--parseDependency, --pd Parse go files inside dependency folder, disabled by default (default: false)
--markdownFiles value, --md value Parse folder containing markdown files to use as description, disabled by default
--codeExampleFiles value, --cef value Parse folder containing code example files to use for the x-codeSamples extension, disabled by default
--parseInternal Parse go files in internal packages, disabled by default (default: false)
--generatedTime Generate timestamp at the top of docs.go, disabled by default (default: false)
--parseDepth value Dependency parse depth (default: 100)
--instanceName value This parameter can be used to name different swagger document instances. It is optional.
--overridesFile value File to read global type overrides from. (default: ".swaggo")
--help, -h show help (default: false)
选项 | 默认值 | 描述 |
---|---|---|
-g | main.go | API通用信息所在Go源文件路径,若是相对路径则基于API解析目录。 |
-d | ./ |
API解析目录 |
--exclude | 空 | 解析扫描时排除的目录,多个目录可使用逗号分割。 |
-p | camelcase | 结构体字段命名规则,三种可选snakecase、camelcase、pascalcase。 |
-o | ./docs |
文件输出目录 |
--parseVendor | 禁用 | 是否解析vendor 目录中的Go源文件 |
--parseDependency | 禁用 | 是否解析依赖目录中的Go源文件 |
--md | - | 指定API的描述信息所使用的MarkDown文件所在的目录 |
--generateTime | 启用 | 是否输出时间到输出文件docs.go 顶部 |
--cef | 禁用 | 解析包含用于x-codeSamples 扩展的代码示例文件的文件夹 |
--parseInternal | 禁用 | 解析internal 包中的Go文件 |
--parseDepth | 100 | 依赖解析深度 |
--instanceName | swagger | 设置文档实例名称 |
若项目根目录下存在main.go
主入口文件,可直接使用swag init
初始化创建docs.go
。若接口注释没有编写在默认的main.go
主入口文件中,可使用-g
标识来告知swag。
例如:
$ swag init -g swag.go
生成文档
生成Swagger文档的步骤
- 在代码中添加注释,先通过注释的
main
方法添加整个项目的一般描述。
例如:添加项目级别的文档
$ vim main.go
package main
import (
"net/http"
"github.com/gorilla/mux"
httpSwagger "github.com/swaggo/http-swagger"
)
// @title RESTful API
// @version 1.0
// @description RESTful API Document
// @host 127.0.0.1:8801
// @BasePath /
func main() {
router := mux.NewRouter()
router.PathPrefix("/swagger").Handler(httpSwagger.WrapHandler)
http.ListenAndServe(":8801", router)
}
- 生成swagger配置文件
完成对项目入口函数main()
注释后, 使用swag init
命令生成Swagger文档。
$ swag init -g main.go
执行成功后会在项目根目录下生成docs
目录,并会根据注解生成最新的配置文件。
- 加载配置文件
入口文件通过导入httpSwagger "github.com/swaggo/http-swagger"
包,即可使用SwaggerUI。使用前必须将swag init
生成的文档配置加载到入口。
$ vim main.go
package main
import (
"net/http"
_ "gwf/docs"
"github.com/gorilla/mux"
httpSwagger "github.com/swaggo/http-swagger"
)
// @title RESTful API
// @version 1.0
// @description RESTful API Document
// @host 127.0.0.1:8801
// @BasePath /
func main() {
router := mux.NewRouter()
router.PathPrefix("/swagger").Handler(httpSwagger.WrapHandler)
http.ListenAndServe(":8801", router)
}
这里关键核心在于导入包的_ "gwf/docs"
位置,_
是一种导入副作用包的方法,意味着代码没有显式地调用包中的任何方法,但可能执行注入注册处理程序之类的操作。
- 运行测试
$ go run main.go
浏览器输入地址 http://127.0.0.1:8801/swagger/index.html ,加载Swagger UI。
Swagger提供了在线编辑器,通过复制配置文件内容来显示UI界面。
- Swagger在线编辑器 https://editor.swagger.io/
通用API信息
主函数采用声明式注释格式包含通用API信息
// @title RESTful API
// @version 1.0
// @description RESTful API Document
// @host 127.0.0.1:8801
// @BasePath /
func main()
- 若想直接在Swagger中调试API,必须填写
@host
、@BasePath
两项。
注释 | 说明 |
---|---|
@title | 应用程序名称,必填。 |
@version | 提供应用程序API的版本 |
@description | 应用程序简短描述 |
@tag.name | 标签名称 |
@tag.description | 标签描述 |
@tag.docs.url | 标签的外部文档URL |
@termsOfService | API服务条款 |
@contact.url | 联系信息的URL,必须采用网址格式。 |
@license.name | 必填,用于API的许可证名称。 |
@license.url | 用于API许可证的URL,必须采用网址格式。 |
@host | 运行API的主机,主机名或IP地址。 |
@BasePath | 运行API的基本路径 |
@accept | API可使用的MIME类型列表 |
@produce | API可以生成的MIME类型列表 |
@query.collection.format | 请求URI Query里数组参数的默认格式,默认csv。 |
@schemes | 空格分割的请求的传输协议 |
@x-name | 扩展的键,必须以x-开头,且只能使用JSON值。 |
处理程序
- 封装HTTP服务器,使用
gorilla/mux
出来路由。 - 为处理程序添加注释并通过Swagger测试
创建入口函数
$ vim main.go
package main
import (
"gwf/router"
"net/http"
)
// @title RESTful API
// @version 1.0
// @description RESTful API Document
// @host 127.0.0.1:8801
// @BasePath /
func main() {
http.ListenAndServe(":8801", router.Register())
}
分离路由实现路由注册
$ vim router/router.go
package router
import (
"gwf/router/admin"
"github.com/gorilla/mux"
)
func Register() *mux.Router {
//创建路由器
r := mux.NewRouter().StrictSlash(true)
//注册路由
admin.Swag(r)
admin.Home(r)
return r
}
创建Swagger服务路由
$ vim router/admin/swag.go
package admin
import (
_ "gwf/docs"
"github.com/gorilla/mux"
httpSwagger "github.com/swaggo/http-swagger"
)
func Swag(r *mux.Router) {
g := r.PathPrefix("/swag")
g.Handler(httpSwagger.WrapHandler)
}
创建后台首页接口并添加Swagger注释
$ vim router/admin/home.go
package admin
import (
"gwf/handler/admin"
"github.com/gorilla/mux"
)
func Home(r *mux.Router) {
g := r.PathPrefix("/admin").Subrouter()
h := admin.NewHome()
{
g.HandleFunc("/", h.Index).Methods("GET").Name("admin_home")
}
}
创建后台后路由对应的处理程序
$ vim handler/admin/home.go
package admin
import (
"gwf/response"
"log"
"net/http"
)
type home struct{}
func NewHome() *home {
return new(home)
}
// @Summary 首页
// @Description 默认首页
// @Tags 后台
// @Accept json
// @Produce json
// @Failure 500 {string} string "{code:500, msg:"failure"}"
// @Success 200 {string} string "{code:200, msg:"ok", data:null}"
// @Router /admin [get]
func (*home) Index(w http.ResponseWriter, r *http.Request) {
log.Printf("%s %s %s\n", r.RemoteAddr, r.RequestURI, r.Method)
w.Header().Set("Content-Type", "application/json;charset=utf-8")
w.Write(response.Ok.Json())
}
统一输出的JSON参数
$ mkdir response && cd response
$ vim response.go
package response
import (
"encoding/json"
"log"
)
var (
Ok = New(200, "操作成功")
Err = New(500, "操作失败")
)
type reply struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
}
// reply 构造函数
func New(code int, msg string) *reply {
return &reply{
Code: code,
Msg: msg,
Data: nil,
}
}
// WithMsg 追加响应消息
func (t *reply) WithMsg(msg string) reply {
return reply{
Code: t.Code,
Msg: msg,
Data: t.Data,
}
}
// WithData 追加响应数据
func (t *reply) WithData(data interface{}) reply {
return reply{
Code: t.Code,
Msg: t.Msg,
Data: data,
}
}
// Json 返回JSON格式的数据
func (t *reply) Json() []byte {
s := &struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
}{
Code: t.Code,
Msg: t.Msg,
Data: t.Data,
}
log.Printf("%+v\n", s)
raw, err := json.Marshal(s)
if err != nil {
log.Println(err)
}
return raw
}
生成最新Swagger文档
$ swag init
浏览器输入地址 http://127.0.0.1:8801/swag/index.html 测试接口
API操作注释
// @Summary 首页
// @Description 默认首页
// @Tags 后台
// @Accept json
// @Produce json
// @Failure 500 {string} string "{code:500, msg:"failure"}"
// @Success 200 {string} string "{code:200, msg:"ok", data:null}"
// @Router /admin [get]
func (*home) Index(w http.ResponseWriter, r *http.Request)
-
@Tags
用来给API分组
注释 | 描述 |
---|---|
@Description | 操作行为的详细说明 |
@Description.markdown | 应用程序的简短描述,该描述从名为endpointname.md 的文件中读取。 |
@Id | 用于标识操作的唯一字符串,在所有API操作中必须唯一。 |
@Tags | 每个API操作的标签列表,以逗号分割。 |
@Summary | 操作的简短摘要 |
@Accept | API可使用的MIME类型列表,Accept仅影响具有请求正文的操作,值必须是"Mime类型"。 |
@Produce | API可以生成的MIME类型的列表,值必须是“Mime类型”。 |
@Param | 空格分隔的参数 |
@Secuirty | API操作的安全性 |
@Success | 空格分割的成功响应 |
@Failure | 空格分割的故障响应 |
@Response | 与@success、@failure作用相同 |
@Header | 空格分割的头字段 |
@Router | 空格分割的路径定义 |
@X-name | 扩展字段必须以x- 开头,只能使用JSON值。 |
@Param
Param
参数格式
@Param 参数名 参数类型 参数数据类型 是否必须 参数描述 其它属性
例如:
@Param id path integer true "自增主键"
@Param who query string true "人名"
@Param name body string true "名称" default(admin)
@Param username formData string true "账户" default(admin)
@Param param body main.JSONParam true "上传的JSON"
参数 | 示例 | 描述 |
---|---|---|
参数名 | name | 解释参数的名字 |
参数类型 | body | 参数类型分为5种 |
参数数据类型 | string | 参数数据类型支持类型4类 |
是否必须 | true | 该参数是否是必须需要的 |
参数描述 | "名称" | 参数的说明文本 |
其它属性 | default(admin) | 额外属性,比如枚举、默认值、值范围等。 |
参数类型支持5种
参数类型 | 描述 |
---|---|
path | 直接拼接在URL中 |
query | 组合在URL中 |
formData | 一般是POST、PUT方法所用 |
body | Accept为JSON时,使用该字段接受JSON类型。 |
header | 请求头中传递的参数 |
参数数据类型支持4种
参数数据类型 | 可选值 |
---|---|
string | string |
integer | int、uint、uint32、uint64 |
number | float32 |
boolean | bool |
额外属性可组合使用
额外属性 | 描述 |
---|---|
Enums(A,B,C) | 枚举值 |
minlength(1) | 最小长度 |
maxlength(20) | 最大长度 |
minium(1) | 最小值 |
maxinum(20) | 最大值 |
default(0) | 默认值 |
@Success
@Success
注释用于指定成功响应的数据,格式为
@Success HTTP响应码 {响应参数类型} 响应数据类型 其它描述
例如:
@Success 200 {object} main.File
@Success 200 {string} string ""
元素 | 描述 |
---|---|
HTTP响应码 | 诸如200、400、500 |
响应参数类型 | - |
响应数据类型 | 返回的数据类型,可以是自定义类型,也可以是JSON。 |
其它描述 | 描述说明 |
@Router
@Router
用于指定路由与HTTP方法,不用添加基础路径。
@Router
格式如下:
@Router /path/to/handler [HTTP方法]
MIME类型
swag
接受所有格式正确的MIME类型,即使匹配*/*
,除此之外swag还接受某些MIME类型的别名。
别名 | MIME |
---|---|
json | application/json |
xml | text/xml |
plain | text/plain |
html | text/html |
mpfd | multipart/form-data |
x-www-form-urlencoded | application/x-www-form-urlencoded |
json-api | application/vnd.api + json |
json-stream | application/x-json-stream |
octet-stream | application/octet-stream |
png | image/png |
jpeg | image/jpeg |
gif | image/gif |