#關於Swaggo

相信很多程式猿和我一樣不喜歡寫API文件。寫程式碼多舒服,寫文件不僅要花費大量的時間,有時候還不能做到面面具全。但API文件是必不可少的,相信其重要性就不用我說了,一份含糊的文件甚至能讓前後端人員打起來。 而今天這篇部落格介紹的swaggo就是讓你只需要專注於程式碼就可以生成完美API文件的工具。廢話說的有點多,我們直接看文章。

或許你使用過Swagger, 而 swaggo就是代替了你手動編寫yaml的部分。只要通過一個命令就可以將註釋轉換成文件,這讓我們可以更加專注於程式碼。

目前swaggo主要實現了swagger 2.0 的以下部分功能:

  • 基本結構(Basic Structure)

  • API 地址與基本路徑(API Host and Base Path)

  • 路徑與操作 (Paths and Operations)

  • 引數描述(Describing Parameters)

  • 請求引數描述(Describing Request Body)

  • 返回描述(Describing Responses)

  • MIME 型別(MIME Types)

  • 認證(Authentication)

  • Basic Authentication

  • API Keys

  • 新增例項(Adding Examples)

  • 檔案上傳(File Upload)

  • 列舉(Enums)

  • 按標籤分組(Grouping Operations With Tags)

  • 擴充套件(Swagger Extensions)

下文內容均以gin-swaggo為例

這裡是demo地址

2020/05/16 更新:

swag 升級到了 v1.6.5,返回資料格式有更新。

最新的請關注官網文件

本文最後,優化部分可以瞭解一下。

#使用使用

#安裝swag-cli-及下載相關包安裝swag cli 及下載相關包

要使用swaggo,首先需要安裝swag cli

    go get -u github.com/swaggo/swag/cmd/swag

然後我們還需要兩個包。

    # gin-swagger 中介軟體
go get github.com/swaggo/gin-swagger
# swagger 內建檔案
go get github.com/swaggo/gin-swagger/swaggerFiles

可以看一下自己安裝的版本

    swag --version
swag version v1.6.5

#在main-go內添加註釋main.go內添加註釋

    package main

    import (
"github.com/gin-gonic/gin"
ginSwagger "github.com/swaggo/gin-swagger"
"github.com/swaggo/gin-swagger/swaggerFiles"
) // @title Swagger Example API
// @version 1.0
// @description This is a sample server celler server.
// @termsOfService https://razeen.me // @contact.name Razeen
// @contact.url https://razeen.me
// @contact.email [email protected] // @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html // @host 127.0.0.1:8080
// @BasePath /api/v1 funcmain() { r := gin.Default()
store := sessions.NewCookieStore([]byte("secret"))
r.Use(sessions.Sessions("mysession", store)) r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) v1 := r.Group("/api/v1")
{
v1.GET("/hello", HandleHello)
v1.POST("/login", HandleLogin)
v1Auth := r.Use(HandleAuth)
{
v1Auth.POST("/upload", HandleUpload)
v1Auth.GET("/list", HandleList)
}
} r.Run(":8080")
}

如上所示,我們需要匯入

    ginSwagger "github.com/swaggo/gin-swagger"
"github.com/swaggo/gin-swagger/swaggerFiles"

同時,添加註釋。其中:

  • titile: 文件標題
  • version: 版本
  • description,termsOfService,contact ... 這些都是一些宣告,可不寫。
  • license.name 額,這個是必須的。
  • host,BasePath: 如果你想直接swagger除錯API,這兩項需要填寫正確。前者為服務文件的埠,ip。後者為基礎路徑,像我這裡就是“/api/v1”。
  • 在原文件中還有securityDefinitions.basic,securityDefinitions.apikey等,這些都是用來做認證的,我這裡暫不展開。

到這裡,我們在mian.go同目錄下執行swag init就可以自動生成文件,如下:

    ➜  swaggo-gin git:(master) ✗ swag init
2019/01/12 21:29:14 Generate swagger docs....
2019/01/12 21:29:14 Generate general API Info
2019/01/12 21:29:14 create docs.go at docs/docs.go

然後我們匯入這個自動生成的docs包,執行:

    package main

    import (
"github.com/gin-gonic/gin"
ginSwagger "github.com/swaggo/gin-swagger"
"github.com/swaggo/gin-swagger/swaggerFiles" _ "github.com/razeencheng/demo-go/swaggo-gin/docs"
) // @title Swagger Example API
// @version 1.0
// ...
    ➜  swaggo-gin git:(master) ✗ go build
➜ swaggo-gin git:(master) ✗ ./swaggo-gin
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. [GIN-debug] [WARNING] Running in"debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode) [GIN-debug] GET /api/v1/hello --> main.HandleHello (3 handlers)
[GIN-debug] POST /api/v1/login --> main.HandleLogin (3 handlers)
[GIN-debug] POST /upload --> main.HandleUpload (4 handlers)
[GIN-debug] GET /list --> main.HandleList (4 handlers)
[GIN-debug] GET /swagger/*any --> github.com/swaggo/gin-swagger.WrapHandler.func1 (4 handlers)
[GIN-debug] Listening and serving HTTP on :8080

瀏覽器開啟http://127.0.0.1:8080/swagger/index.html, 我們可以看到如下文件標題已經生成。

#在Handle函式上添加註釋在Handle函式上添加註釋

接下來,我們需要在每個路由處理函式上加上註釋,如:

    // @Summary 測試SayHello
// @Description 向你說Hello
// @Tags 測試
// @Accept mpfd
// @Produce json
// @Param who query string true "人名"
// @Success 200 {string} string "{"msg": "hello Razeen"}"
// @Failure 400 {string} string "{"msg": "who are you"}"
// @Router /hello [get]
funcHandleHello(c *gin.Context) {
who := c.Query("who") if who == "" {
c.JSON(http.StatusBadRequest, gin.H{"msg": "who are u?"})
return
} c.JSON(http.StatusOK, gin.H{"msg": "hello " + who})
}

我們再次swag init, 執行一下。

此時,該API的相關描述已經生成了,我們點選Try it out還可以直接測試該API。

是不是很好用,當然這並沒有結束,這些註釋欄位,我們一個個解釋。

這些註釋對應出現在API文件的位置,我在上圖中已經標出,這裡我們主要詳細說說下面引數:

#TagsTags

Tags 是用來給API分組的。

#AcceptAccept

接收的引數型別,支援表單(mpfd) , JSON(json)等,更多如下表。

#ProduceProduce

返回的資料結構,一般都是json, 其他支援如下表:

Mime Type宣告application/jsonjsontext/xmlxmltext/plainplainhtmlhtmlmultipart/form-datampfdapplication/x-www-form-urlencodedx-www-form-urlencodedapplication/vnd.api+jsonjson-apiapplication/x-json-streamjson-streamapplication/octet-streamoctet-streamimage/pngpngimage/jpegjpegimage/gifgif

#ParamParam

引數,從前往後分別是:

@Param who query string true “人名”

@Param 1.引數名``2.引數型別``3.引數資料型別``4.是否必須``5.引數描述``6.其他屬性

1.引數名

引數名就是我們解釋引數的名字。

2.引數型別

引數型別主要有四種:

path 該型別引數直接拼接在URL中,如DemoHandleGetFile

    // @Param id path integer true "檔案ID"
``` -
`query` 該型別引數一般是組合在URL中的,如[Demo](https://github.com/razeencheng/demo-go/blob/master/swaggo-gin/handle.go)中`HandleHello` ```golang // @Param who query string true "人名"
``` `formData` 該型別引數一般是`POST,PUT`方法所用,如[Demo](https://github.com/razeencheng/demo-go/blob/master/swaggo-gin/handle.go)中`HandleLogin` ```golang
// @Param user formData string true "使用者名稱" default(admin)
``` `body` 當`Accept`是`JSON`格式時,我們使用該欄位指定接收的JSON型別 ```golang
// @Param param body main.JSONParams true "需要上傳的JSON"
``` 3.引數資料型別 資料型別主要支援一下幾種: - string (string)
- integer (int, uint, uint32, uint64)
- number (float32)
- boolean (bool) 注意,如果你是上傳檔案可以使用`file`, 但引數型別一定是`formData`, 如下: ```golang
// @Param file formData file true "檔案"
``` 4.是否是必須 表明該引數是否是必須需要的,必須的在文件中會黑體標出,測試時必須填寫。 5.引數描述 就是引數的一些說明 6.其他屬性 除了上面這些屬性外,我們還可以為該引數填寫一些額外的屬性,如列舉,預設值,值範圍等。如下: ```golang
列舉
// @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" mininum(1) maxinum(10) 設定預設值
// @Param default query string false "string default" default(A)

而且這些引數是可以組合使用的,如:

    // @Param enumstring query string false "string enums" Enums(A, B, C) default(A)
``` ##### [#Success](#Success)Success 指定成功響應的資料。格式為: > // @Success `1.HTTP響應碼``{2.響應引數型別}``3.響應資料型別``4.其他描述` 1.HTTP響應碼 也就是200,400,500那些。 2.響應引數型別 / 3.響應資料型別 返回的資料型別,可以是自定義型別,可以是json。 - 自定義型別 在平常的使用中,我都會返回一些指定的模型序列化JSON的資料,這時,就可以這麼 ```golang
// @Success 200 {object} main.File
``` 其中,模型直接用`包名.模型`即可。你會說,假如我返回模型陣列怎麼辦?這時你可以這麼寫: ```golang
// @Success 200 {anrry} main.File
``` 將如你只是返回其他的資料格式可如下寫: ```golang
// @Success 200 {string} string ""

4.其他描述

可以新增一些說明。

#FailureFailure

​ 同Success。

#RouterRouter

​ 指定路由與HTTP方法。格式為:

// @Router /path/to/handle [HTTP方法]

​ 不用加基礎路徑哦。

#生成文件與測試生成文件與測試

其實上面已經穿插的介紹了。

main.go下執行swag init即可生成和更新文件。

點選文件中的Try it out即可測試。 如果部分API需要登陸,可以Try登陸介面即可。

#優化優化

看到這裡,基本可以使用了。但文件一般只是我們測試的時候需要,當我的產品上線後,介面文件是不應該給使用者的,而且帶有介面文件的包也會大很多(swaggo是直接build到二進位制裡的)。

想要處理這種情況,我們可以在編譯的時候優化一下,如利用build tag來控制是否編譯文件。

main.go宣告swagHandler,並在該引數不為空時才加入路由:


package main //... var swagHandler gin.HandlerFunc funcmain(){
// ... if swagHandler != nil {
r.GET("/swagger/*any", swagHandler)
} //...
}

同時,我們將該引數在另外加了build tag的包中初始化。


// +build doc package main import (
_ "github.com/razeencheng/demo-go/swaggo-gin/docs" ginSwagger "github.com/swaggo/gin-swagger"
"github.com/swaggo/gin-swagger/swaggerFiles"
) funcinit() {
swagHandler = ginSwagger.WrapHandler(swaggerFiles.Handler)
}
``` 之後我們就可以使用`go build -tags "doc"`來打包帶文件的包,直接`go build`來打包不帶文件的包。 你會發現,即使我這麼小的Demo,編譯後的大小也要相差19M ! ```shell
➜ swaggo-gin git:(master) ✗ go build
➜ swaggo-gin git:(master) ✗ ll swaggo-gin
-rwxr-xr-x 1 xxx staff 15M Jan 13 00:23 swaggo-gin
➜ swaggo-gin git:(master) ✗ go build -tags "doc"
➜ swaggo-gin git:(master) ✗ ll swaggo-gin
-rwxr-xr-x 1 xxx staff 34M Jan 13 00:24 swaggo-gin

文章到這裡也就結束了,完整的Demo地址在這裡

本文章摘自https://razeencheng.com/post/go-swagger.html