Gin學(xué)習(xí)
go-swagger
Gin-APi json
1 go-swagger
前言
在前后端分離的項(xiàng)目開發(fā)過程中,如果后端同學(xué)能夠提供一份清晰明了的接口文檔,那么就能極大地提高大家的溝通效率和開發(fā)效率。那如何維護(hù)接口文檔,歷來都是令人頭痛的,感覺很浪費(fèi)精力,而且后續(xù)接口文檔的維護(hù)也十分耗費(fèi)精力。在很多年以前,也流行用word等工具寫接口文檔,這里面的問題很多,如格式不統(tǒng)一、后端人員消費(fèi)精力大、文檔的時(shí)效性也無法保障。
針對(duì)這類問題,最好是有一種方案能夠既滿足我們輸出文檔的需要又能隨代碼的變更自動(dòng)更新,Swagger正是那種能幫我們解決接口文檔問題的工具。
Swagger介紹
Swagger是基于標(biāo)準(zhǔn)的 OpenAPI 規(guī)范進(jìn)行設(shè)計(jì)的,本質(zhì)是一種用于描述使用json表示的Restful Api的接口描述語(yǔ)言,只要照著這套規(guī)范去編寫你的注解或通過掃描代碼去生成注解,就能生成統(tǒng)一標(biāo)準(zhǔn)的接口文檔和一系列 Swagger 工具。Swagger包括自動(dòng)文檔,代碼生成和測(cè)試用例生成。
安裝Swagger
1、安裝
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="arduino" cid="n15" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">arduino
復(fù)制代碼go get -u github.com/swaggo/swag/cmd/swag</pre>
在macOS中安裝 swag需要執(zhí)行如下命令:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="bash" cid="n17" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">bash
復(fù)制代碼mv $GOPATH/bin/swag /usr/local/go/bin</pre>
2、檢測(cè)是否安裝成功
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="ruby" cid="n19" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">ruby復(fù)制代碼$ swag -v
swag version v1.8.4</pre>
3、安裝gin-swagger擴(kuò)展
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="shell" cid="n21" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">shell復(fù)制代碼 go get -u -v github.com/swaggo/files
$ go get -u -v github.com/alecthomas/template</pre>
使用
使用gin-swagger為你的代碼自動(dòng)生成接口文檔,一般需要下面三個(gè)步驟:
按照swagger要求給接口代碼添加聲明式注釋。
使用swag工具掃描代碼自動(dòng)生成api接口文檔數(shù)據(jù)。
使用gin-swagger渲染在線接口文檔頁(yè)面。
1、添加注釋
go-swapper注解規(guī)范說明:
注:注解詳情可參見官網(wǎng)文檔Swagger Documentation
| 注解 | 描述 |
|---|---|
| @Summary | 摘要 |
| @Produce | API 可以產(chǎn)生的 MIME 類型的列表,MIME 類型你可以簡(jiǎn)單的理解為響應(yīng)類型,例如:json、xml、html 等等 |
| @Param | 參數(shù)格式,從左到右分別為:參數(shù)名、入?yún)㈩愋汀?shù)據(jù)類型、是否必填、注釋 |
| @Success | 響應(yīng)成功,從左到右分別為:狀態(tài)碼、參數(shù)類型、數(shù)據(jù)類型、注釋 |
| @Failure | 響應(yīng)失敗,從左到右分別為:狀態(tài)碼、參數(shù)類型、數(shù)據(jù)類型、注釋 |
| @Router | 路由,從左到右分別為:路由地址,HTTP 方法 |
參數(shù)類型Param Type
object (struct)
string (string)
integer (int, uint, uint32, uint64)
number (float32)
boolean (bool)
array
數(shù)據(jù)類型Data Type
string (string)
integer (int, uint, uint32, uint64)
number (float32)
boolean (bool)
user defined struct
示例demo:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="sql" cid="n83" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">sql復(fù)制代碼package main
import (
"github.com/gin-gonic/gin"
"github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
_ "github/mwqnice/swag/docs" // 千萬不要忘了導(dǎo)入把你上一步生成的docs
)
type Article struct{
ID uint32 gorm:"primary_key" json:"id"
CreatedBy string json:"created_by"
ModifiedBy string json:"modified_by"
CreatedOn uint32 json:"created_on"
ModifiedOn uint32 json:"modified_on"
DeletedOn uint32 json:"deleted_on"
IsDel uint8 json:"is_del"
Title string json:"title"
Desc string json:"desc"
Content string json:"content"
CoverImageUrl string json:"cover_image_url"
State uint8 json:"state"
}
func NewArticle() Article {
return Article{}
}
func main() {
r := gin.Default()
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
r.Run(":8088")
}
// @Summary 獲取單個(gè)文章
// @Produce json
// @Param id path int true "文章ID"
// @Success 200 {object} Article "成功"
// @Failure 400 {object} string "請(qǐng)求錯(cuò)誤"
// @Failure 500 {object} string "內(nèi)部錯(cuò)誤"
// @Router /api/v1/articles/{id} [get]
func (a Article) Get(c *gin.Context) {
}
// @Summary 獲取多個(gè)文章
// @Produce json
// @Param name query string false "文章名稱"
// @Param tag_id query int false "標(biāo)簽ID"
// @Param state query int false "狀態(tài)"
// @Param page query int false "頁(yè)碼"
// @Param page_size query int false "每頁(yè)數(shù)量"
// @Success 200 {object} Article "成功"
// @Failure 400 {object} string "請(qǐng)求錯(cuò)誤"
// @Failure 500 {object} string "內(nèi)部錯(cuò)誤"
// @Router /api/v1/articles [get]
func (a Article) List(c *gin.Context) {
return
}
// @Summary 創(chuàng)建文章
// @Produce json
// @Param tag_id body string true "標(biāo)簽ID"
// @Param title body string true "文章標(biāo)題"
// @Param desc body string false "文章簡(jiǎn)述"
// @Param cover_image_url body string true "封面圖片地址"
// @Param content body string true "文章內(nèi)容"
// @Param created_by body int true "創(chuàng)建者"
// @Param state body int false "狀態(tài)"
// @Success 200 {object} Article "成功"
// @Failure 400 {object} string "請(qǐng)求錯(cuò)誤"
// @Failure 500 {object} string "內(nèi)部錯(cuò)誤"
// @Router /api/v1/articles [post]
func (a Article) Create(c *gin.Context) {
}
// @Summary 更新文章
// @Produce json
// @Param tag_id body string false "標(biāo)簽ID"
// @Param title body string false "文章標(biāo)題"
// @Param desc body string false "文章簡(jiǎn)述"
// @Param cover_image_url body string false "封面圖片地址"
// @Param content body string false "文章內(nèi)容"
// @Param modified_by body string true "修改者"
// @Success 200 {object} Article "成功"
// @Failure 400 {object} string "請(qǐng)求錯(cuò)誤"
// @Failure 500 {object} string "內(nèi)部錯(cuò)誤"
// @Router /api/v1/articles/{id} [put]
func (a Article) Update(c *gin.Context) {
return
}
// @Summary 刪除文章
// @Produce json
// @Param id path int true "文章ID"
// @Success 200 {string} string "成功"
// @Failure 400 {object} string "請(qǐng)求錯(cuò)誤"
// @Failure 500 {object} string "內(nèi)部錯(cuò)誤"
// @Router /api/v1/articles/{id} [delete]
func (a Article) Delete(c *gin.Context) {
return
}</pre>
2、生成接口文檔數(shù)據(jù)
格式化swag注解
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="shell" cid="n86" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">shell
復(fù)制代碼$ swag fmt</pre>
在項(xiàng)目根目錄執(zhí)行以下命令,使用swag工具生成接口文檔數(shù)據(jù)。
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="csharp" cid="n88" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">csharp
復(fù)制代碼$ swag init</pre>
執(zhí)行完上述命令后,如果你寫的注釋格式?jīng)]問題,此時(shí)你的項(xiàng)目根目錄下會(huì)多出一個(gè)docs文件夾。
./docs
├── docs.go
├── swagger.json
└── swagger.yaml
3、引入gin-swagger渲染文檔數(shù)據(jù)
然后在項(xiàng)目代碼中注冊(cè)路由的地方按如下方式引入gin-swagger相關(guān)內(nèi)容:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="go" cid="n96" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">go復(fù)制代碼import (
"github.com/gin-gonic/gin"
"github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
_ "github/mwqnice/swag/docs" // 千萬不要忘了導(dǎo)入把你上一步生成的docs
)
//添加swagger訪問路由
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))</pre>
啟動(dòng)項(xiàng)目,在瀏覽器中輸入地址:http://127.0.0.1:8088/swagger/index.html
2 Gin-APi json
方法1:
基于GetRawData()和map獲取。
示例:
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="go" cid="n103" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">//需要導(dǎo)入包
import (
"encoding/json"
"github.com/gin-gonic/gin"
)
// Login 假如有一個(gè)用戶登錄接口
func Login(c *gin.Context) {
data, _ := c.GetRawData()
var body map[string]string
_ = json.Unmarshal(data, &body)
//獲取json中的key,注意使用["key"]獲取
name:= body["name"]
email := body["email"]
}</pre>
方法2:(推薦使用)
基于BindJSON()和結(jié)構(gòu)體獲取。
通過BindJSON()可見將json請(qǐng)求體綁定到一個(gè)結(jié)構(gòu)體上。(通常綁定到一個(gè)匿名結(jié)構(gòu)體)
示例:
<pre spellcheck="false" class="md-fences mock-cm md-end-block" lang="go" cid="n109" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: pre-wrap; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">//需要導(dǎo)入包
import (
"github.com/gin-gonic/gin"
)
// Login 假如有一個(gè)用戶登錄接口
func Login(c *gin.Context) {
//定義匿名結(jié)構(gòu)體,字段與json字段對(duì)應(yīng)
var body struct {
Email string json:"email"
Name string json:"name"
}
//綁定json和結(jié)構(gòu)體
if err := c.BindJSON(&body); err != nil {
return
}
//獲取json中的key,注意使用 . 訪問
email := body.Email
name := body.Name
}</pre>