swagger是一套基于OpenAPI规范构建的开源工具,使用RestApi。swagger-ui 呈现出来的是一份可交互式的API文档,可以直接在文档页面尝试API的调用。
gin-swagger 是基于注释生成 API 文档,项目地址:https://github.com/swaggo/swag。
//go版本1.16之前使用该命令
go get -u github.com/swaggo/swag/cmd/swag
//go版本1.16版本以及之后的版本使用该命令
go install github.com/swaggo/swag/cmd/swag@latest
swag -h
NAME:
swag.exe - Automatically generate RESTful API documentation with Swagger 2.0 for Go.
USAGE:
swag.exe [global options] command [command options] [arguments...]
VERSION:
v1.8.8
COMMANDS:
init, i 创建docs.go
fmt, f 格式化swag注释
help, h 展示命令列表或者查看命令帮助
GLOBAL OPTIONS:
--help, -h show help (default: false)
--version, -v print the version (default: false)
swag init -h
NAME:
swag.exe init - Create docs.go
USAGE:
swag.exe init [command options] [arguments...]
OPTIONS:
--quiet, -q 禁用日志,默认 false
--generalInfo value, -g value 写入通用 API信息的 go文件路径,默认 main.go
--dir value, -d value 需要解析文件的路径,用逗号分隔,通用信息路径必须在第一个,默认是"./"
--exclude value 搜索时排除的路径和文件,用逗号分隔
--propertyStrategy value, -p value 属性命名策略,有蛇式、驼峰式,帕斯卡式,默认驼峰式
--output value, -o value 生成文件的输出路径(swagger.json, swagger.yaml and docs.go),默认"./docs"
--outputTypes value, --ot value 生成文件的输出类型(docs.go、swagger.json、swagger.yaml),如go、json、yaml 默认"go,json,yaml"
--parseVendor 是否解析 vendor 文件夹下的过文件,默认 false
--parseDependency, --pd 是否解析依赖路径下的 go文件,默认 false
--markdownFiles value, --md value 指定包含 markdown 文件的路径,可解析为API说明,默认禁用
--codeExampleFiles value, --cef value 指定包含用于 x-codeSamples 扩展的代码示例文件的文件夹,默认禁用
--parseInternal 是否解析内部包中的 go文件,默认 false
--generatedTime 是否在 docs.go 顶部生成时间戳,默认 false
--parseDepth value 解析依赖深度,默认100
--requiredByDefault 是否设置所有文件需要验证,默认false
--instanceName value 设置swagger文档实例名,可选。
--overridesFile value 全局类型重写文件,默认 ".swaggo"
--parseGoList 是否通过 'go list' 解析,默认 true
--tags value, -t value 以逗号分隔的标记列表,用于筛选生成文档的API。如果标记前缀为“!”,则具有该标记的API将被排除
--help, -h 帮助
声明:使用方法大部分是参考swaggo git仓库的说明文档,仓库地址:https://github.com/swaggo/swag
swag init
生成 Swagger 2.0文件后,导入如下几个包 :import "github.com/swaggo/gin-swagger" // gin-swagger middleware
import "github.com/swaggo/files" // swagger embed files
main.go
代码中添加通用API注释:// @title Swagger Example API
// @version 1.0
// @description This is a sample server celler server.
// @termsOfService http://swagger.io/terms/
// @contact.name API Support
// @contact.url http://www.swagger.io/support
// @contact.email [email protected]
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host localhost:8080
// @BasePath /api/v1
// @securityDefinitions.basic BasicAuth
func main() {
r := gin.Default()
c := controller.NewController()
v1 := r.Group("/api/v1")
{
accounts := v1.Group("/accounts")
{
accounts.GET(":id", c.ShowAccount)
accounts.GET("", c.ListAccounts)
accounts.POST("", c.AddAccount)
accounts.DELETE(":id", c.DeleteAccount)
accounts.PATCH(":id", c.UpdateAccount)
accounts.POST(":id/images", c.UploadAccountImage)
}
//...
}
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
r.Run(":8080")
}
//...
此外,还可以动态设置一些通用API信息。生成的代码包docs
导出SwaggerInfo
变量,使用该变量可以通过编码的方式设置标题、描述、版本、主机和基础路径。使用Gin的示例:
package main
import (
"github.com/gin-gonic/gin"
"github.com/swaggo/files"
"github.com/swaggo/gin-swagger"
"./docs" // docs is generated by Swag CLI, you have to import it.
)
// @contact.name API Support
// @contact.url http://www.swagger.io/support
// @contact.email [email protected]
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
func main() {
// programmatically set swagger info
docs.SwaggerInfo.Title = "Swagger Example API"
docs.SwaggerInfo.Description = "This is a sample server Petstore server."
docs.SwaggerInfo.Version = "1.0"
docs.SwaggerInfo.Host = "petstore.swagger.io"
docs.SwaggerInfo.BasePath = "/v2"
docs.SwaggerInfo.Schemes = []string{"http", "https"}
r := gin.New()
// use ginSwagger middleware to serve the API docs
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
r.Run()
}
controller
代码中添加API操作注释package controller
import (
"fmt"
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/swaggo/swag/example/celler/httputil"
"github.com/swaggo/swag/example/celler/model"
)
// ShowAccount godoc
// @Summary Show an account
// @Description get string by ID
// @Tags accounts
// @Accept json
// @Produce json
// @Param id path int true "Account ID"
// @Success 200 {object} model.Account
// @Failure 400 {object} httputil.HTTPError
// @Failure 404 {object} httputil.HTTPError
// @Failure 500 {object} httputil.HTTPError
// @Router /accounts/{id} [get]
func (c *Controller) ShowAccount(ctx *gin.Context) {
id := ctx.Param("id")
aid, err := strconv.Atoi(id)
if err != nil {
httputil.NewError(ctx, http.StatusBadRequest, err)
return
}
account, err := model.AccountOne(aid)
if err != nil {
httputil.NewError(ctx, http.StatusNotFound, err)
return
}
ctx.JSON(http.StatusOK, account)
}
// ListAccounts godoc
// @Summary List accounts
// @Description get accounts
// @Tags accounts
// @Accept json
// @Produce json
// @Param q query string false "name search by q" Format(email)
// @Success 200 {array} model.Account
// @Failure 400 {object} httputil.HTTPError
// @Failure 404 {object} httputil.HTTPError
// @Failure 500 {object} httputil.HTTPError
// @Router /accounts [get]
func (c *Controller) ListAccounts(ctx *gin.Context) {
q := ctx.Request.URL.Query().Get("q")
accounts, err := model.AccountsAll(q)
if err != nil {
httputil.NewError(ctx, http.StatusNotFound, err)
return
}
ctx.JSON(http.StatusOK, accounts)
}
//...
$ swag init
在使用的时候发现一个问题, V1.8.8版本使用格式化工具进行格式化的时候,会使用制表符对齐,但是 swag init 解析的时候解析不出来通用API注释,手动使用空格替换制表符后即可正常解析。后来更新到V1.8.9修复了该问题,但是格式化完后对齐没有之前美观了。
可以针对Swag的注释自动格式化,就像go fmt
命令一样。
用法:
swag fmt
排除路径:
swag fmt -d ./ --exclude ./internal
使用swag fmt
时,为了确保格式正确,需要保证为函数提供文档注释。这是由于swag fmt
只允许在标准文档注释之后使用tabs
缩进。
例如:
// ListAccounts lists all existing accounts
//
// @Summary List accounts
// @Description get accounts
// @Tags accounts
// @Accept json
// @Produce json
// @Param q query string false "name search by q" Format(email)
// @Success 200 {array} model.Account
// @Failure 400 {object} httputil.HTTPError
// @Failure 404 {object} httputil.HTTPError
// @Failure 500 {object} httputil.HTTPError
// @Router /accounts [get]
func (c *Controller) ListAccounts(ctx *gin.Context) {
注释 | 说明 | 示例 |
---|---|---|
title | 必填。程序标题 | // @title Swagger Example API |
version | 必填。 程序API版本 | // @version 1.0 |
description | 程序简短描述 | // @description This is a sample server celler server. |
tag.name | 标签名 | // @tag.name This is the name of the tag |
tag.description | 标签描述 | // @tag.description Cool Description |
tag.docs.url | 标签的外部文档URL | // @tag.docs.url https://example.com |
tag.docs.description | 标签的外部文档说明 | // @tag.docs.description Best example documentation |
termsOfService | API服务条款 | // @termsOfService http://swagger.io/terms/ |
contact.name | 公开的API联系信息 | // @contact.name API Support |
contact.url | 联系信息URL。必须采用网址格式 | // @contact.url http://www.swagger.io/support |
contact.email | 联系人/组织的电子邮件地址。必须采用电子邮件地址的格式。 | // @contact.email [email protected] |
license.name | 必填。 用于API的许可证名称 | // @license.name Apache 2.0 |
license.url | 用于API的许可证URL。必须采用网址格式 | // @license.url http://www.apache.org/licenses/LICENSE-2.0.html |
host | 运行API的主机(主机名或者IP地址) | // @host localhost:8080 |
BasePath | 运行API的基本路径 | // @BasePath /api/v1 |
accept | API可以使用的MIME类型列表。注意,Accept仅影响具有body 的请求,例如POST、PUT和PATCH。值必须是Mime类型中的一种 |
// @accept json |
produce | API可以生成的MIME类型列表。值必须是Mime类型中的一种 | // @produce json |
query.collection.format | 请求URI query里数组参数的默认格式:csv,multi,pipes,tsv,ssv。 如果未设置,则默认为csv | // @query.collection.format multi |
schemes | 用空格分隔的请求的传输协议 | // @schemes http https |
x-name | 扩展的键必须以x-开头,并且只能使用json值 | // @x-example-key {“key”: “value”} |
如果文档中的短字符串不足以完整表达,或者需要展示图片,代码示例等类似的内容,则可能需要使用Markdown描述。要使用Markdown描述,请使用一下注释。
注释 | 说明 | 示例 |
---|---|---|
title | 必填。程序标题 | // @title Swagger Example API |
version | 必填。 程序API版本 | // @version 1.0 |
description.markdown | 程序的简短描述。从api.md文件解析。这是@description的替代用法 | // @description.markdown No value needed, this parses the description from api.md |
tag.name | 标签名 | // @tag.name This is the name of the tag |
tag.description.markdown | 标签的说明。这是tag.description的替代用法。 该描述将从名为tagname.md的文件中读取 | // @tag.description.markdown |
注释 | 说明 |
---|---|
description | 操作行为的详细说明 |
description.markdown | 应用程序的简短描述。会从文件中读取描述。例如@description.markdown details 将加载details.md |
id | 用于标识API操作的唯一字符串。在所有API操作中必须是唯一的 |
tags | API所属的标签列表,用逗号分隔 |
summary | 操作的简短摘要 |
accept | API可以使用的MIME类型列表。注意,Accept仅影响具有body 的请求,例如POST、PUT和PATCH。值必须是Mime类型中的一种 |
produce | API可以生成的MIME类型列表.。值必须是Mime类型中的一种 |
param | 以空格分隔的参数。 参数名 , 参数类型, 数据类型, 是否强制 , "注释" , 属性(可选) |
security | API操作的安全性 |
success | 以空格分隔的成功响应。 状态码 , {参数类型} , 数据类型,"注释" , 注意这里的参数类型和 @param的参数类型不同,这里和数据类型有点相似,可以取值 {string} , {array} , {object} 等 ,同时不要忘记要带一对花括号 |
failure | 以空格分隔的失败响应。 状态码 , {参数类型} , 数据类型,"注释" , 注意这里的参数类型和 @param的参数类型不同,这里和数据类型有点相似,可以取值 {string} , {array} , {object} 等 ,同时不要忘记要带一对花括号 |
response | 和 success 、failure 用法相同 |
header | 以空格分隔的头字段。 状态码 , {参数类型} , header键值, "注释" , 注意这里的参数类型和 @param的参数类型不同,这里和数据类型有点相似,可以取值 {string} , {array} , {object} 等 ,同时不要忘记要带一对花括号 |
router | 以空格分隔的路径定义。 path ,[httpMethod] |
x-name | 扩字段必须以x- 开头,并且只能接受json值 |
x-codeSample | 可选的Markdown用法。将“file”作为参数。然后会在给定文件夹中搜索类似summary 的文件 |
deprecated | 标记API为废弃状态 |
swag
接受所有格式正确的MIME类型,即匹配 /。
另外,swag
也会接收一些如下所示的别名:
别名 | 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 |
注释 | 说明 | 参数 | 例子 |
---|---|---|---|
securitydefinitions.basic | Basic auth. | // @securityDefinitions.basic BasicAuth | |
securitydefinitions.apikey | API key auth. | in, name, description | // @securityDefinitions.apikey ApiKeyAuth |
securitydefinitions.oauth2.application | OAuth2 application auth. | tokenUrl, scope, description | // @securitydefinitions.oauth2.application OAuth2Application |
securitydefinitions.oauth2.implicit | OAuth2 implicit auth. | authorizationUrl, scope, description | // @securitydefinitions.oauth2.implicit OAuth2Implicit |
securitydefinitions.oauth2.password | OAuth2 password auth. | tokenUrl, scope, description | // @securitydefinitions.oauth2.password OAuth2Password |
securitydefinitions.oauth2.accessCode | OAuth2 access code auth. | tokenUrl, authorizationUrl, scope, description | // @securitydefinitions.oauth2.accessCode OAuth2AccessCode |
参数注释 | 示例 |
---|---|
in | // @in header |
name | // @name Authorization |
tokenUrl | // @tokenUrl https://example.com/oauth/token |
authorizationurl | // @authorizationurl https://example.com/oauth/authorize |
scope.hoge | // @scope.write Grants write access |
description | // @description OAuth protects our entity endpoints |
// @Param enumstring query string false "string enums" Enums(A, B, C)
// @Param enumint query int false "int enums" Enums(1, 2, 3)
// @Param enumnumber query number false "int enums" Enums(1.1, 1.2, 1.3)
// @Param string query string false "string valid" minlength(5) maxlength(10)
// @Param int query int false "int valid" minimum(1) maximum(10)
// @Param default query string false "string default" default(A)
// @Param example query string false "string example" example(string)
// @Param collection query []string false "string collection" collectionFormat(multi)
// @Param extensions query []string false "string collection" extensions(x-example=test,x-nullable)
也适用于结构体字段:
type Foo struct {
Bar string `minLength:"4" maxLength:"16" example:"random string"`
Baz int `minimum:"10" maximum:"20" default:"15"`
Qux []string `enums:"foo,bar,baz"`
}
字段名 | 类型 | 说明 |
---|---|---|
validate | string |
参数验证。可选值有:required,optional |
default | * | 如果未提供指定参数,服务器将使用此参数默认值。例如,使用"count"控制每页结果的数量,如果客户端未在请求中传入此参数,则可以设置参数默认值为100。(注意:默认参数对必填参数无效。)请参阅https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2.与JSON模式不同,该值必须符合为该参数定义的type。 |
maximum | number |
See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.2. |
minimum | number |
See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.3. |
multipleOf | number |
See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.1. |
maxLength | integer |
See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.1. |
minLength | integer |
See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.2.2. |
enums | [*] | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.1. |
format | string |
上面提到的类型的扩展格式。有关更多详细信息,请参见数据类型格式 |
collectionFormat | string |
Determines the format of the array if type array is used. Possible values are:
csv . |
example | * | Declares the example for the parameter value |
extensions | string |
Add extension to parameters. |
可以在常规api描述或路由定义中添加跨越多行的描述,如下所示:
// @description This is the first line
// @description This is the second line
// @description And so forth.
// @Success 200 {array} model.Account <-- This is a user defined struct.
package model
type Account struct {
ID int `json:"id" example:"1"`
Name string `json:"name" example:"account name"`
}
可以在函数体中声明请求响应结构体。You can declare your request response structs inside a function body。
必须遵循命名约定<包名>.<函数名>.<结构体名称>
。
package main
// @Param request body main.MyHandler.request true "query params"
// @Success 200 {object} main.MyHandler.response
// @Router /test [post]
func MyHandler() {
type request struct {
RequestField string
}
type response struct {
ResponseField string
}
}
// JSONResult's data field will be overridden by the specific type proto.Order
@success 200 {object} jsonresult.JSONResult{data=proto.Order} "desc"
type JSONResult struct {
Code int `json:"code" `
Message string `json:"message"`
Data interface{} `json:"data"`
}
type Order struct { //in `proto` package
Id uint `json:"id"`
Data interface{} `json:"data"`
}
@success 200 {object} jsonresult.JSONResult{data=[]proto.Order} "desc"
@success 200 {object} jsonresult.JSONResult{data=string} "desc"
@success 200 {object} jsonresult.JSONResult{data=[]string} "desc"
@success 200 {object} jsonresult.JSONResult{data1=string,data2=[]string,data3=proto.Order,data4=[]proto.Order} "desc"
type DeepObject struct { //in `proto` package
...
}
@success 200 {object} jsonresult.JSONResult{data1=proto.Order{data=proto.DeepObject},data2=[]proto.Order{data=[]proto.DeepObject}} "desc"
// @Success 200 {string} string "ok"
// @failure 400 {string} string "error"
// @response default {string} string "other error"
// @Header 200 {string} Location "/entity/1"
// @Header 200,400,default {string} Token "token"
// @Header all {string} Token2 "token2"
/// ...
// @Param group_id path int true "Group ID"
// @Param account_id path int true "Account ID"
// ...
// @Router /examples/groups/{group_id}/accounts/{account_id} [get]
/// ...
// @Param group_id path int true "Group ID"
// @Param user_id path int true "User ID"
// ...
// @Router /examples/groups/{group_id}/user/{user_id}/address [put]
// @Router /examples/user/{user_id}/address [put]
type Account struct {
ID int `json:"id" example:"1"`
Name string `json:"name" example:"account name"`
PhotoUrls []string `json:"photo_urls" example:"http://test/image/1.jpg,http://test/image/2.jpg"`
}
body
的SchemaExample
// @Param email body string true "message/rfc822" SchemaExample(Subject: Testmail\r\n\r\nBody Message\r\n)
// Account model info
// @Description User account information
// @Description with user id and username
type Account struct {
// ID this is userid
ID int `json:"id"`
Name string `json:"name"` // This is Name
}
#708解析器只处理以@Description
属性开头的结构注释。
但它会按原样写入所有结构字段注释。
因此,生成的swagger文档如下:
"Account": {
"type":"object",
"description": "User account information with user id and username"
"properties": {
"id": {
"type": "integer",
"description": "ID this is userid"
},
"name": {
"type":"string",
"description": "This is Name"
}
}
}
swaggertype
标签更改字段类型#201
type TimestampTime struct {
time.Time
}
///implement encoding.JSON.Marshaler interface
func (t *TimestampTime) MarshalJSON() ([]byte, error) {
bin := make([]byte, 16)
bin = strconv.AppendInt(bin[:0], t.Time.Unix(), 10)
return bin, nil
}
func (t *TimestampTime) UnmarshalJSON(bin []byte) error {
v, err := strconv.ParseInt(string(bin), 10, 64)
if err != nil {
return err
}
t.Time = time.Unix(v, 0)
return nil
}
///
type Account struct {
// Override primitive type by simply specifying it via `swaggertype` tag
ID sql.NullInt64 `json:"id" swaggertype:"integer"`
// Override struct type to a primitive type 'integer' by specifying it via `swaggertype` tag
RegisterTime TimestampTime `json:"register_time" swaggertype:"primitive,integer"`
// Array types can be overridden using "array," format
Coeffs []big.Float `json:"coeffs" swaggertype:"array,number"`
}
#379
type CerticateKeyPair struct {
Crt []byte `json:"crt" swaggertype:"string" format:"base64" example:"U3dhZ2dlciByb2Nrcw=="`
Key []byte `json:"key" swaggertype:"string" format:"base64" example:"U3dhZ2dlciByb2Nrcw=="`
}
生成的swagger文档如下:
"api.MyBinding": {
"type":"object",
"properties":{
"crt":{
"type":"string",
"format":"base64",
"example":"U3dhZ2dlciByb2Nrcw=="
},
"key":{
"type":"string",
"format":"base64",
"example":"U3dhZ2dlciByb2Nrcw=="
}
}
}
如果您使用的是生成的文件,可能无法使用swaggertype标记以支持自定义类型,或swaggerignore
标记。
通过使用--overridesFile
传递映射到swag
,可以在任何地方使用一种类型代替另一种类型。默认情况下,如果当前目录中存在“.swaggo”文件,则将使用该文件。
Go代码:
type MyStruct struct {
ID sql.NullInt64 `json:"id"`
Name sql.NullString `json:"name"`
}
.swaggo
:
// Replace all NullInt64 with int
replace database/sql.NullInt64 int
// Don't include any fields of type database/sql.NullString in the swagger docs
skip database/sql.NullString
指令的具体含义在注释(以“//”开头)注明了、“replace path/to/a.type path/to/b.type”和“skip path/to/a.type”。
(请注意,必须提供指向任何命名类型的完整路径,以防止在多个包定义具有相同名称的类型时出现问题)。
提供:
"types.MyStruct": {
"id": "integer"
}
swaggerignore
标签排除字段type Account struct {
ID string `json:"id"`
Name string `json:"name"`
Ignored int `swaggerignore:"true"`
}
type Account struct {
ID string `json:"id" extensions:"x-nullable,x-abc=def,!x-omitempty"` // extensions fields must start with "x-"
}
生成的swagger
文档如下:
"Account": {
"type": "object",
"properties": {
"id": {
"type": "string",
"x-nullable": true,
"x-abc": "def",
"x-omitempty": false
}
}
}
type Resp struct {
Code int
}//@name Response
通用API信息
// @securityDefinitions.basic BasicAuth
// @securitydefinitions.oauth2.application OAuth2Application
// @tokenUrl https://example.com/oauth/token
// @scope.write Grants write access
// @scope.admin Grants read and write access to administrative information
单个API操作
// @Security ApiKeyAuth
使用AND
条件
// @Security ApiKeyAuth
// @Security OAuth2Application[write, admin]
使用OR
条件
// @Security ApiKeyAuth || firebase
// @Security OAuth2Application[write, admin] || APIKeyAuth
type Example struct {
// Sort order:
// * asc - Ascending, from A to Z.
// * desc - Descending, from Z to A.
Order string `enums:"asc,desc"`
}
默认情况下,swag
命令使用如下三种不同的文件生成Swagger规范:
如果要限制应生成的一组文件类型,可以使用--outputTypes
(-ot
)标志。默认值为go,json,yaml
-输出类型用逗号分隔。要将输出限制为go
和yaml
文件,可以编写go,yaml
。使用完整的命令swag init--outputTypes go,yaml
。