相信很多程序猿和我一樣不喜歡寫API文檔。寫代碼多舒服,寫文檔不僅要花費大量的時間,有時候還不能做到面面具全。但API文檔是必不可少的,相信其重要性就不用我說了,一份含糊的文檔甚至能讓前后端人員打起來。 而今天這篇博客介紹的swaggo就是讓你只需要專注于代碼就可以生成完美API文檔的工具。廢話說的有點多,我們直接看文章。
go語言中文文檔:www.topgoer.com
大概最后文檔效果是這樣的:

1.1.1. 關于Swaggo
或許你使用過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 AuthenticationAPI Keys
- 添加實例(Adding Examples)
- 文件上傳(File Upload)
- 枚舉(Enums)
- 按標簽分組(Grouping Operations With Tags)
- 擴展(Swagger Extensions)
下文內容均以gin-swaggo為例 這里是demo地址
1.1.2. 使用
安裝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
在main.go內添加注釋
package mainimport ( "net/http" "github.com/gin-gonic/gin" _ "github.com/student/0509/docs" 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://www.topgoer.com// @contact.name www.topgoer.com// @contact.url https://www.topgoer.com// @contact.email me@razeen.me// @license.name Apache 2.0// @license.url http://www.apache.org/licenses/LICENSE-2.0.html// @host 127.0.0.1:8080// @BasePath /api/v1func main() { r := gin.Default() 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就可以自動生成文檔,如下:
E:goprojectsrcgithub.comopgoer>swag init2020/05/13 16:28:02 Generate swagger docs....2020/05/13 16:28:02 Generate general API Info, search dir:./2020/05/13 16:28:02 create docs.go at docs/docs.go2020/05/13 16:28:02 create swagger.json at docs/swagger.json2020/05/13 16:28:02 create swagger.yaml at docs/swagger.yaml
然后我們在main.go導入這個自動生成的docs包,運行:
package mainimport ( "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// ...
E:goprojectsrcgithub.comopgoer>go run main.go[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 /swagger/*any --> github.com/swaggo/gin-swagger.CustomWrapHandler.func1 (3 handlers)[GIN-debug] GET /api/v1/hello --> main.HandleHello (3 handlers)[GIN-debug] Listening and serving HTTP on :8080
瀏覽器打開http://127.0.0.1:8080/swagger/index.html, 我們可以看到如下文檔標題已經生成。

1.1.3. 在Handle函數上添加注釋
接下來,我們需要在每個路由處理函數上加上注釋,如:
package mainimport ( "net/http" "github.com/gin-gonic/gin" _ "github.com/student/0509/docs" 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://www.topgoer.com// @contact.name www.topgoer.com// @contact.url https://www.topgoer.com// @contact.email me@razeen.me// @license.name Apache 2.0// @license.url http://www.apache.org/licenses/LICENSE-2.0.html// @host 127.0.0.1:8080// @BasePath /api/v1func main() { r := gin.Default() 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")}// @Summary 測試SayHello// @Description 向你說Hello// @Tags 測試// @Accept json// @Param who query string true "人名"// @Success 200 {string} string "{"msg": "hello Razeen"}"// @Failure 400 {string} string "{"msg": "who are you"}"// @Router /hello [get]func HandleHello(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文檔的位置,我在上圖中已經標出,這里我們主要詳細說說下面參數:
Tags
Tags 是用來給API分組的。
Accept
接收的參數類型,支持表單(mpfd) 和 JSON(json)
Produce
返回的數據結構,一般都是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
Param
參數,從前往后分別是:
@Param 1.參數名 2.參數類型 3.參數數據類型 4.是否必須 5.參數描述 6.其他屬性
- 1.參數名參數名就是我們解釋參數的名字。
- 2.參數類型參數類型主要有三種:path 該類型參數直接拼接在URL中,如Demo中HandleGetFile:// @Param id path integer true "文件ID" query 該類型參數一般是組合在URL中的,如Demo中HandleHello// @Param who query string true "人名" formData 該類型參數一般是POST,PUT方法所用,如Demo中HandleLogin// @Param user formData string true "用戶名" default(admin)
- 3.參數數據類型數據類型主要支持一下幾種:string (string)integer (int, uint, uint32, uint64)number (float32)boolean (bool)注意,如果你是上傳文件可以使用file, 但參數類型一定是formData, 如下:// @Param file formData file true "文件"
- 4.是否是必須表明該參數是否是必須需要的,必須的在文檔中會黑體標出,測試時必須填寫。
- 5.參數描述就是參數的一些說明
- 6.其他屬性除了上面這些屬性外,我們還可以為該參數填寫一些額外的屬性,如枚舉,默認值,值范圍等。如下:枚舉 // @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 1.HTTP響應碼 {2.響應參數類型} 3.響應數據類型 4.其他描述
- 1.HTTP響應碼也就是200,400,500那些。
- 2.響應參數類型 / 3.響應數據類型返回的數據類型,可以是自定義類型,可以是json。自定義類型在平常的使用中,我都會返回一些指定的模型序列化JSON的數據,這時,就可以這么寫:// @Success 200 {object} main.File 其中,模型直接用包名.模型即可。你會說,假如我返回模型數組怎么辦?這時你可以這么寫:// @Success 200 {anrry} main.File json將如你只是返回其他的json數據可如下寫:// @Success 200 {string} json ""
- 4.其他描述可以添加一些說明。
Failure
? 同Success。
Router
? 指定路由與HTTP方法。格式為:
// @Router /path/to/handle [HTTP方法]
? 不用加基礎路徑哦。
1.1.4. 生成文檔與測試
其實上面已經穿插的介紹了。
在main.go下運行swag init即可生成和更新文檔。
點擊文檔中的Try it out即可測試。 如果部分API需要登陸,可以Try登陸接口即可。
1.1.5. 優化
看到這里,基本可以使用了。但文檔一般只是我們測試的時候需要,當我的產品上線后,接口文檔是不應該給用戶的,而且帶有接口文檔的包也會大很多(swaggo是直接build到二進制里的)。
想要處理這種情況,我們可以在編譯的時候優化一下,如利用build tag來控制是否編譯文檔。
在main.go聲明swagHandler,并在該參數不為空時才加入路由:
package main//...var swagHandler gin.HandlerFuncfunc main(){ // ... if swagHandler != nil { r.GET("/swagger/*any", swagHandler) } //...}
同時,我們將該參數在另外加了build tag的包中初始化。
// +build docpackage mainimport ( _ "github.com/razeencheng/demo-go/swaggo-gin/docs" ginSwagger "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles")func init() { swagHandler = ginSwagger.WrapHandler(swaggerFiles.Handler)}
之后我們就可以使用go build -tags "doc"來打包帶文檔的包,直接go build來打包不帶文檔的包。
你會發現,即使我這么小的Demo,編譯后的大小也要相差19M !
? 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地址在這里。
相關鏈接
- Swaggo Github
- Swagger