5 分钟
Go Swagger
简述
swagger/OpenAPI,是一套业界标准的 HTTP API 描述标准。
go-swagger,是 Swagger 2.0 的 Go 语言的实现,以 cli 或 library 的方式,提供了如下能力:
- 从 swagger 规范文件生成服务器
- 从 swagger 规范文件生成客户端
- 从 swagger 规范文件(alpha 阶段)生成 CLI(命令行工具)
- 支持 jsonschema 和 swagger 提供的大多数功能,包括多态性
- 从带注释的 go 代码生成 swagger 规范文件
- 使用 swagger 规范文件的其他工具
- 强大的自定义功能,带有供应商扩展和可自定义的模板
安装
go install github.com/go-swagger/go-swagger/cmd/swagger@latest
swagger version
其他安装方式,参见:官方文档
样例说明
新建项目
mkdir go-swagger-learn
go mod init github.com/rectcircle/go-swagger-learn
场景
假设我们要开发一个根据 UserID 获取用户信息的接口
GET /users/{id}
# response 200
{
"code": 0,
"message": "success",
"data": {
"id": 1,
"name":"abc"
}
}
希望使用 go-swagger 实现如下功能。
- 根据代码生成 swagger 规范文件
- 根据 swagger 规范文件生成 client 代码
从代码生成 swagger 规范文件
例子
编写代码和注释
首先定义 domain (简化起见,我们吧 dto 和 接口定义在了一起)
domain/user.go
package domain
import (
"context"
)
// User 实体
// swagger:model User
type User struct {
// User ID
ID int `json:"id"`
// 用户名
Name string `json:"name"`
}
type UserService interface {
// swagger:route GET /users/{id} users GetOneUser
//
// 通过 ID 获取 User 信息
//
// 这是接口的详细描述
//
// Responses:
// 200: GetUserResponse
Get(ctx context.Context, id int) (*User, error)
}
定义 http 请求和返回的声明
domain/user_http.go
package domain
// swagger:parameters GetOneUser
type GetUserRequest struct {
// User ID 参数
//
// Required: true
// in: path
ID int `json:"id"`
}
type BaseResponseBodyForSwagger struct {
// 错误码
Code int `json:"code"`
// 错误信息
Message string `json:"message"`
}
// swagger:response GetUserResponse
type GetUserResponse struct {
// in: body
Body struct {
BaseResponseBodyForSwagger
Data User `json:"data"`
}
// Body GetUserResponseBody
}
最后,添加 swagger:meta
注解
domain/doc.go
// Package domian go swagger learn
//
// 这是描述
//
// Terms Of Service:
//
// 这是服务条款
//
// Host: localhost
// Version: 0.0.1
//
// swagger:meta
package domain
执行命令生成 swagger 规范文件
swagger generate spec -o ./api/swagger.json
生成文件内容
{
"swagger": "2.0",
"info": {
"description": "这是描述",
"title": "go swagger learn",
"termsOfService": "这是服务条款",
"version": "0.0.1"
},
"host": "localhost",
"paths": {
"/users/{id}": {
"get": {
"description": "这是接口的详细描述",
"tags": [
"users"
],
"summary": "通过 ID 获取 User 信息",
"operationId": "GetOneUser",
"parameters": [
{
"type": "integer",
"format": "int64",
"x-go-name": "ID",
"description": "User ID 参数",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"$ref": "#/responses/GetUserResponse"
}
}
}
}
},
"definitions": {
"User": {
"description": "User 实体",
"type": "object",
"properties": {
"id": {
"description": "User ID",
"type": "integer",
"format": "int64",
"x-go-name": "ID"
},
"name": {
"description": "用户名",
"type": "string",
"x-go-name": "Name"
},
"status": {
"description": "状态\nactive StatusActive\ninactive StatusInactive",
"type": "string",
"enum": [
"active",
"inactive"
],
"x-go-enum-desc": "active StatusActive\ninactive StatusInactive",
"x-go-name": "Status"
}
},
"x-go-package": "github.com/rectcircle/go-swagger-learn/domain"
}
},
"responses": {
"GetUserResponse": {
"description": "",
"schema": {
"type": "object",
"properties": {
"code": {
"description": "错误码",
"type": "integer",
"format": "int64",
"x-go-name": "Code"
},
"data": {
"$ref": "#/definitions/User"
},
"message": {
"description": "错误信息",
"type": "string",
"x-go-name": "Message"
}
}
}
}
}
}
启动 server 观察文档
swagger serve api/swagger.json
简单说明
- 在代码中使用
// swagger:
表示接下来的注释是 swagger 的注释,会用来生成 swagger 规范文件。 - 一个 http 接口的声明包含三个部分,接口描述,接口请求描述,接口返回描述。
- 接口描述注释:
// swagger:route [method] [path pattern] [?tag1 tag2 tag3] [operation id]
,允许位于任何位置 - 接口请求注释:
// swagger:parameters [operationid1 operationid2]
必须在一个结构体声明上方,在内部通过in: body
声明哪个字段是 body,注意字段名需要通过json
注解声明。 - 接口返回注释:
// swagger:response [?response name]
必须在一个结构体声明上方,在内部通过in: body
声明哪个字段是 body,需要在// swagger:route
下方关联上 response name。 - 枚举类型注释:
// swagger:enum [Type]
在type Xxx string
或type Xxx int
上方可以声明一个枚举类型 - 字符串格式声明注释:
// swagger:strfmt [name]
,参见:官方文档
命令行使用
Usage:
swagger [OPTIONS] generate spec [spec-OPTIONS]
generate a swagger spec document from a go application
Application Options:
-q, --quiet silence logs
--log-output=LOG-FILE redirect logs to file
Help Options:
-h, --help Show this help message
[spec command options]
-w, --work-dir= the base path to use (default: .)
-t, --tags= build tags
-m, --scan-models includes models that were annotated with 'swagger:model'
--compact when present, doesn't prettify the json
-o, --output= the file to write to
-i, --input= an input swagger file with which to merge
-c, --include= include packages matching pattern
-x, --exclude= exclude packages matching pattern
--include-tag= include routes having specified tags (can be specified many times)
--exclude-tag= exclude routes having specified tags (can be specified many times)
--exclude-deps exclude all dependencies of project
注释规范
参考:官方文档
常见场景
上传文件
假设我们实现一个简单上传文件接口,该接口请求体包含两部分
- 文件内容
额外的一些元数据
interface Xxx { // swagger:route POST /uploads uploads Upload // // 上传文件 // // Consumes: // - multipart/form-data // // Security: // token: // // Responses: // 200: UploadResponse // 实现的时候使用流式上传以节约内存 Upload(ctx context.Context, meta UploadMeta, data io.ReadCloser) (*FileInfo, error) } // UploadRequest 上传文件的请求 // swagger:parameters Upload type UploadRequest struct { // 上传文件请求中的元数据部分,JSON 解构 // // 结构参见 [UploadMeta model](#model-UploadMeta) (Content-Type 为 application/json) // 特别说明:由于 Swagger/OpenAPI 2.0 multipart/form-data 的限制,这里只能定义为 string,且不支持指定每个部分的 Content-Type,参见: // [Swagger/OpenAPI 3.0 multipart-content 说明](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.1.md#special-considerations-for-multipart-content) | // [stackoverflow](https://stackoverflow.com/questions/44323585/how-to-send-a-json-object-as-part-of-a-multipart-request-in-swagger-editor) | // [Swagger/OpenAPI 2.0 upload file](https://swagger.io/docs/specification/2-0/file-upload/) // // Required: true // in: formData Data string // 上传的文件内容 // // 参见:[github issue](https://github.com/go-swagger/go-swagger/issues/1887) // // Required: false // in: formData // swagger:file File *bytes.Buffer } type BaseResponseBody struct { // 错误码 Code int `json:"code"` // 错误信息 Message string `json:"message"` } // UploadResponse 返回某个 UploadResponse // swagger:response UploadResponse type UploadResponse struct { // in: body Body struct { BaseResponseBody Data FileInfo `json:"data"` } } type UploadMeta struct { //... } type FileInfo struct { //... }
支持 *string
类型
type XxxRequest struct {
// 命名
// Extensions:
// ---
// x-nullable: true
Name *string `json:"name"`
}
参见:
从 swagger 规范文件生成 client 代码
例子
mkdir -p client/internal
# swagger generate client -f api/swagger.json --client-package=client/internal/client --model-package=client/internal/domain
swagger generate client -f api/swagger.json --target=client/internal
go mod tidy
注意,model 不能复用我们手写的 domain
下的代码文件,因为 go-swagger 生成代码依赖 model 实现序列化和反序列函数。手动写的的是不存在这些的。
生成到 client/internal 的原因是,某些场景希望再包装一层,提供更加优化的接口,再暴露给其他人使用(多数情况下,没有必要)。
命令行使用
Usage:
swagger [OPTIONS] generate client [client-OPTIONS]
generate all the files for a client library
Application Options:
-q, --quiet silence logs
--log-output=LOG-FILE redirect logs to file
Help Options:
-h, --help Show this help message
[client command options]
-c, --client-package= the package to save the client specific code (default: client)
-P, --principal= the model to use for the security principal
--default-scheme= the default scheme for this API (default: http)
--principal-is-interface the security principal provided is an interface, not a struct
--default-produces= the default mime type that API operations produce (default: application/json)
--default-consumes= the default mime type that API operations consume (default: application/json)
--skip-models no models will be generated when this flag is specified
--skip-operations no operations will be generated when this flag is specified
-A, --name= the name of the application, defaults to a mangled value of info.title
Options common to all code generation commands:
-f, --spec= the spec file to use (default swagger.{json,yml,yaml})
-t, --target= the base directory for generating the files (default: ./)
--template=[stratoscale] load contributed templates
-T, --template-dir= alternative template override directory
-C, --config-file= configuration file to use for overriding template options
-r, --copyright-file= copyright file used to add copyright header
--additional-initialism= consecutive capitals that should be considered intialisms
--allow-template-override allows overriding protected templates
--skip-validation skips validation of spec prior to generation
--dump-data when present dumps the json for the template generator instead of generating files
--strict-responders Use strict type for the handler return value
--with-expand expands all $ref's in spec prior to generation (shorthand to --with-flatten=expand)
--with-flatten=[minimal|full|expand|verbose|noverbose|remove-unused] flattens all $ref's in spec prior to generation (default: minimal, verbose)
Options for model generation:
-m, --model-package= the package to save the models (default: models)
-M, --model= specify a model to include in generation, repeat for multiple (defaults to all)
--existing-models= use pre-generated models e.g. github.com/foobar/model
--strict-additional-properties disallow extra properties when additionalProperties is set to false
--keep-spec-order keep schema properties order identical to spec file
--struct-tags= the struct tags to generate, repeat for multiple (defaults to json)
Options for operation generation:
-O, --operation= specify an operation to include, repeat for multiple (defaults to all)
--tags= the tags to include, if not specified defaults to all
-a, --api-package= the package to save the operations (default: operations)
--with-enum-ci allow case-insensitive enumerations
--skip-tag-packages skips the generation of tag-based operation packages, resulting in a flat generation