API 文档 #
使用 Swagger 生成 API 文档 #
Swagger 是基于 OpenAPI 规范的 API 文档工具。
OpenAPI 是一个 API 规范,它的前身就是 Swagger 规范,目前最新的 OpenAPI 规范是 OpenAPI 3.0(也就是 Swagger 2.0 规范)。
Swagger 编辑器 #
Swagger 编辑是一个在线的 API 文档编辑器,可以在其中编写 OpenAPI 规范,并实时预览 API 文档。
基于代码自动生成 Swagger 文档 #
Go 生成 Swagger 文档常用的工具有两个,分别是 swag 和 go-swagger。
推荐使用 go-swagger:
- go-swagger 提供了更灵活、更多的功能来描述 API,可以生成客户端和服务器端代码。
- 使用 swag 的话,每一个 API 都需要有一个冗长的注释,有时候代码注释比代码还要长,但是通过 go-swagger 可以将代码和注释分开编写,可以使代码保持简洁,清晰易读,而且可以把 API 定义放在一个目录中,方便管理。
安装 go-swagger #
$ go get -u github.com/go-swagger/go-swagger/cmd/swagger
$ swagger version
version: v0.30.3
commit: ecf6f05b6ecc1b1725c8569534f133fa27e9de6b
命令格式为 swagger [OPTIONS] <command>
。
swagger
提供的子命令:
子命令 | 描述 |
---|---|
diff | 对比两个 swagger 文档的差异 |
expand | 展开 swagger 定义文档中的 $ref |
flatten | 展平 swagger 文档 |
generate | 生成 swagger 文档,客户端,服务端代码 |
ini | 初始化一个 swagger 定义文档 |
mix | 合并 swagger 文档 |
serv | 启动 http 服务,用来查看 swagger 文档 |
validate | 验证 swagger 第一文件是否正确 |
使用 #
go-swagger 通过解析源码中的注释来生成 Swagger 文档。
注释语法:
注释语法 | 描述 |
---|---|
swagger:meta | 定义全局基本信息 |
swagger:route | 定义路由信息 |
swagger:parameters | API 请求参数 |
swagger:response | API 响应参数 |
swagger:model | 可以复用的 Go 数据结构 |
swagger:allOf | 嵌入其他 Go 结构体 |
swagger:strfmt | 格式化的字符串 |
swagger:ignore | 需要忽略的结构体 |
swagger generate
命令会找到 main
函数,然后遍历所有源码文件,解析源码中与 Swagger
相关的注释,然后自动生成 swagger.json/swagger.yaml
文件。
package main
import (
"fmt"
"log"
"net/http"
"github.com/gin-gonic/gin"
"github.com/shipengqi/idm/swagger/api"
// This line is necessary for go-swagger to find your docs!
_ "github.com/shipengqi/idm/swagger/docs"
)
var users []*api.User
func main() {
r := gin.Default()
r.POST("/users", Create)
r.GET("/users/:name", Get)
log.Fatal(r.Run(":8081"))
}
// Create a user.
func Create(c *gin.Context) {
var user api.User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"message": err.Error(), "code": 10001})
return
}
for _, u := range users {
if u.Name == user.Name {
c.JSON(http.StatusBadRequest, gin.H{"message": fmt.Sprintf("user %s already exist", user.Name), "code": 10001})
return
}
}
users = append(users, &user)
c.JSON(http.StatusOK, user)
}
// Get return user details.
func Get(c *gin.Context) {
username := c.Param("name")
for _, u := range users {
if u.Name == username {
c.JSON(http.StatusOK, u)
return
}
}
c.JSON(http.StatusBadRequest, gin.H{"message": fmt.Sprintf("user %s not exist", username), "code": 10002})
}
swagger/api/user.go
:
package api
// User represents body of User request and response.
type User struct {
// User's name.
// Required: true
Name string `json:"name"`
// User's nickname.
// Required: true
Nickname string `json:"nickname"`
// User's address.
Address string `json:"address"`
// User's email.
Email string `json:"email"`
}
Required: true
说明字段是必须的。
另外一个 Go 包中编写带 go-swagger 注释的 API 文档。 先创建一个目录 swagger/docs
。在 swagger/docs
创建 doc.go
文件,提供基本的 API 信息:
// Package docs awesome.
//
// Documentation of our awesome API.
//
// Schemes: http, https
// BasePath: /
// Version: 0.1.0
// Host: some-url.com
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// Security:
// - basic
//
// SecurityDefinitions:
// basic:
// type: basic
//
// swagger:meta
package docs
注意最后以 swagger:meta
注释结束。
编写完 doc.go
文件后, 编写 API 的定义文件 swagger/docs/user.go
:
package docs
import (
v1 "github.com/shipengqi/idm/api/apiserver/v1"
metav1 "github.com/shipengqi/idm/api/meta/v1"
)
// swagger:route GET /users/{name} Users getUserRequest
//
// Get details for specified user.
//
// Get details for specified user according to input parameters.
//
// Responses:
// default: errResponse
// 200: getUserResponse
// swagger:route GET /users Users listUserRequest
//
// List users.
//
// List users.
//
// Responses:
// default: errResponse
// 200: listUserResponse
// List users request.
// swagger:parameters listUserRequest
type listUserRequestParamsWrapper struct {
// in:query
metav1.ListOptions
}
// List users response.
// swagger:response listUserResponse
type listUserResponseWrapper struct {
// in:body
Body v1.UserList
}
// User response.
// swagger:response getUserResponse
type getUserResponseWrapper struct {
// in:body
Body v1.User
}
// swagger:parameters createUserRequest updateUserRequest
type userRequestParamsWrapper struct {
// User information.
// in:body
Body v1.User
}
// swagger:parameters deleteUserRequest getUserRequest updateUserRequest
type userNameParamsWrapper struct {
// Username.
// in:path
Name string `json:"name"`
}
// ErrResponse defines the return messages when an error occurred.
// swagger:response errResponse
type errResponseWrapper struct {
// in:body
Body response.Response
}
// Return nil json object.
// swagger:response okResponse
type okResponseWrapper struct{}
swagger:route
:描述一个 API,格式为swagger:route [method] [url path pattern] [?tag1 tag2 tag3] [operation id]
,tag 可以是多个,相同 tag 的 API 在 Swagger 文档中会被分为一组。operation id 会和swagger:parameters
的定义进行匹配,就是该 API 的请求参数。swagger:route
下面的一行是该 API 的描述,需要以.
为结尾。responses:
定义了 API 的返回参数,例如当 HTTP 状态码是 200 时,返回createUserResponse
,createUserResponse
会和swagger:response
的定义进行匹配,匹配成功的swagger:response
就是该 API 返回 200 状态码时的返回。swagger:response
:定义了 API 的返回,格式为swagger:response [?response name]
.例如getUserResponseWrapper
中有一个Body
字段,其注释为// in:body
,说明该参数是在 HTTP Body 中返回。swagger:response
上的注释是 response 的描述。api.User
会被 go-swagger 解析为 Example Value 和 Model,不需要重复编写。swagger:parameters
:定义了 API 的请求参数,格式为swagger:parameters [operationid1 operationid2]
。例如userRequestParamsWrapper
。userRequestParamsWrapper
上的注释是请求参数的描述。
进入 swagger
目录,执行如下命令,生成 Swagger API 文档:
$ swagger generate spec -o swagger.yaml
-o
:指定要输出的文件名。swagger 会根据文件名后缀.yaml
或者.json
,决定生成的文件格式为 YAML 或 JSON。
启动 HTTP 服务:
$ swagger serve --no-open -F=redoc --port 36666 swagger.yaml
–no-open
:-–no-open
禁止调用浏览器打开 URL。-F
:指定文档的风格,可选swagger
和redoc
。redoc
格式更加易读和清晰。–port
:指定启动的 HTTP 服务监听端口。
在浏览器查看 API 文档:
还可以使用下面的命令将生成的 swagger.yaml
转换为 swagger.json
:
$ swagger generate spec -i ./swagger.yaml -o ./swagger.json