Beego中Swagger實現API
1、安裝Beego
$ export GO111MODULE=on
$ export GOPROXY=https://goproxy.io
$ go get github.com/astaxie/beego
$ go get github.com/beego/bee
安裝完之后,bee
可執行文件默認存放在 $GOPATH/bin
里面,所以需要把 $GOPATH/bin
添加到環境變量中
2、新建工程
與bee new 工程名
方法新建項目不同,生成api應用框架有特定的命令
(經測試,new生成的工程也可以實現路由接口,但是接口無法提交結構體字段,使用serverjson提交時無數據顯示,因此建議使用api生成框架,應用Swagger)
$ cd go/src #為了在項目中使用go mod,在此文件下新建項目
$ bee api testapi(工程名)
├── conf
│ ├── app.conf //配置信息,需默認設置EnableDocs = true
├── controllers //控制器,負責處理項目邏輯
│ ├── object.go
│ └── user.go
├── lastupdate.tmp
├── main.go //主函數入口
├── models //數據模型
│ ├── object.go
│ └── user.go
├── routers //路由
│ ├── commentsRouter_controllers.go
│ └── router.go
├── swagger //自動化文檔,實現接口的定義
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── index.html
│ ├── oauth2-redirect.html
│ ├── swagger.json
│ ├── swagger-ui-bundle.js
│ ├── swagger-ui-bundle.js.map
│ ├── swagger-ui.css
│ ├── swagger-ui.css.map
│ ├── swagger-ui.js
│ ├── swagger-ui.js.map
│ ├── swagger-ui-standalone-preset.js
│ ├── swagger-ui-standalone-preset.js.map
│ └── swagger.yml
├── testapi
└── tests
└── default_test.go
運行命令
$ bee run -gendoc=true -downdoc=true
此處需要注意的是,api生成的工程和new生成的工程不同,api生成的工程默認從/go/src下讀取,因此工程新建時需要在src文件夾下新建,原因是工程不再使用go module控制依賴,因此如果需要兼容,需要在src文件下新建。否則會報錯找不到依賴。
運行成功后訪問:
http://127.0.0.1:8080/swagger/ #注意此處為127.0.0.1,而不是localhost,涉及CORS跨域問題
3、設計接口,注解路由
swagger采用注解路由的方式實現接口,主要涉及兩個步驟:
3.1、設置routers/route.go
目前自動化文檔只支持如下的寫法的解析,其他寫法函數不會自動解析,即 namespace+Include 的寫法,而且只支持二級解析,一級版本號,二級分別表示應用模塊,自動化文檔采用CommentRouterPath對注解路由生成,Beego會在啟動的時候掃描文件生成路由,存放在routers下,具體內容如下:
-
API全局設置
必須設置在
routers/router.go
中,文件的注釋,最頂部:全局的注釋如上所示,是顯示給全局應用的設置信息,有如下這些設置
- @APIVersion
- @Title
- @Description
- @Contact
- @TermsOfServiceUrl
- @License
- @LicenseUrl
-
路由設置
只支持二級解析,一級版本號,二級分別表示應用模塊
//route.go
// @APIVersion 1.0.0
// @Title beego Test API
// @Description beego has a very cool tools to autogenerate documents for your API
// @Contact astaxie@gmail.com
// @TermsOfServiceUrl http://beego.me/
// @License Apache 2.0
// @LicenseUrl http://www.apache.org/licenses/LICENSE-2.0.html
package routers
import (
"github.com/astaxie/beego"
"jingjinjiapi/controllers"
)
func init() {
//add route
ns := beego.NewNamespace("/v1",
beego.NSNamespace("/object",
beego.NSInclude(
&controllers.ObjectController{},
),
),
beego.NSNamespace("/user",
beego.NSInclude(
&controllers.UserController{},
),
),
)
beego.AddNamespace(ns)
}
路由設置后,經過后續步驟,可以通過訪問 http://127.0.0.1:8080/v1/user訪問user相關內容,原理類似。
3.2、controllers中注釋編寫
在控制器文件中下的每個controller中編寫函數,注釋寫在函數之上,注釋的內容就是我們要實現接口的功能。包括接口含義,傳遞參數,返回結果等。
-
@Title
這個 API 所表達的含義,是一個文本,空格之后的內容全部解析為 title
-
@Description
這個 API 詳細的描述,是一個文本,空格之后的內容全部解析為 Description
-
@Param
參數,表示需要傳遞到服務器端的參數,有五列參數,使用空格或者 tab 分割,五個分別表示的含義如下
- 參數名
- 參數類型,可以有的值是 formData、query、path、body、header,formData 表示是 post 請求的數據,query 表示帶在 url 之后的參數,path 表示請求路徑上得參數,header 表示帶在 header 信息中得參數,body表示是一個raw數據請求,比如結構體的方式傳遞。
- 參數類型
- 是否必須
- 注釋
-
@Success
成功返回給客戶端的信息,三個參數,第一個是 status code。第二個參數是返回的類型,必須使用 {} 包含,第三個是返回的對象或者字符串信息,如果是 {object} 類型,那么 bee 工具在生成 docs 的時候會掃描對應的對象,這里填寫的是想對你項目的目錄名和對象,例如
models.ZDTProduct.ProductList
就表示/models/ZDTProduct
目錄下的ProductList
對象。三個參數必須通過空格分隔
-
@Failure
失敗返回的信息,包含兩個參數,使用空格分隔,第一個表示 status code,第二個表示錯誤信息
-
@router
路由信息,包含兩個參數,使用空格分隔,第一個是請求的路由地址,支持正則和自定義路由,和之前的路由規則一樣,第二個參數是支持的請求方法,放在
[]
之中,如果有多個方法,那么使用,
分隔。
此處具體記錄幾個例子
3.2.1、POST+參數(body) + 直接訪問
post請求 http://127.0.0.1/v1/user , post內容為models.User,作為數據主體提交,結果返回user.id
// @Title CreateUser
// @Description create users
// @Param body body models.User true "body for user content"
// @Success 200 {int} models.User.Id
// @Failure 403 body is empty
// @router / [post]
func (u *UserController) Post() {
var user models.User
json.Unmarshal(u.Ctx.Input.RequestBody, &user)
uid := models.AddUser(user)
u.Data["json"] = map[string]string{"uid": uid}
u.ServeJSON()
}
3.2.2、POST+參數(path)+提交內容(formData)
post請求 http://127.0.0.1/v1/user/{userid} ,post內容分兩部分,一部分為path路徑上的參數,一部分為提交的表單內容。
// @Title CreateUser
// @Description create users
// @Param userid path string true "user id"
// @Param name formData string true "user name"
// @Param status formData string true "user status"
// @Success 200 {string} success
// @Failure 403 error
// @router /:userid [post]
func (u *UserController) Post() {
uid := u.GetString(":userid")
//解析表單數據,兩種方法
//1、GetString方法
name := u.GetString("name")
status := u.GetString("status")
//2、beego提供的parseForm方法解析到結構體
//定義接收結構體user
//err := u.ParseForm(&user)
u.Data["json"] = "delete success!"
u.ServeJSON()
}
3.2.3、Get 直接訪問
Get請求http://127.0.0.1/v1/user/ Get所有user信息
// @Title GetAll
// @Description get all Users
// @Success 200 {object} models.User
// @router / [get]
func (u *UserController) GetAll() {
users := models.GetAllUsers()
u.Data["json"] = users
u.ServeJSON()
}
3.2.4、Get+參數(path)
Get請求 http://127.0.0.1/v1/user/{uid} 獲取指定uid用戶信息
// @Title Get
// @Description get user by uid
// @Param uid path string true "The key for staticblock"
// @Success 200 {object} models.User
// @Failure 403 :uid is empty
// @router /:uid [get]
func (u *UserController) Get() {
uid := u.GetString(":uid")
if uid != "" {
user, err := models.GetUser(uid)
if err != nil {
u.Data["json"] = err.Error()
} else {
u.Data["json"] = user
}
}
u.ServeJSON()
}
3.2.5、Get+參數(query)
Get請求 http://127.0.0.1/v1/user/login?username=123&password=456 url上外加層級,並獲取查詢字段
// @Title Login
// @Description Logs user into the system
// @Param username query string true "The username for login"
// @Param password query string true "The password for login"
// @Success 200 {string} login success
// @Failure 403 user not exist
// @router /login [get]
func (u *UserController) Login() {
username := u.GetString("username") // 區別於path,此處獲取沒有“:”
password := u.GetString("password")
if models.Login(username, password) {
u.Data["json"] = "login success"
} else {
u.Data["json"] = "user not exist"
}
u.ServeJSON()
}
3.2.6、Put+參數(path)
Put請求 http://127.0.0.1/v1/user/{uid} 提交內容body,更新用戶信息。
// @Title Update
// @Description update the user
// @Param uid path string true "The uid you want to update"
// @Param body body models.User true "body for user content"
// @Success 200 {object} models.User
// @Failure 403 :uid is not int
// @router /:uid [put]
func (u *UserController) Put() {
uid := u.GetString(":uid")
if uid != "" {
var user models.User
json.Unmarshal(u.Ctx.Input.RequestBody, &user)
uu, err := models.UpdateUser(uid, &user)
if err != nil {
u.Data["json"] = err.Error()
} else {
u.Data["json"] = uu
}
}
u.ServeJSON()
}
3.2.7、Delete+參數(path)
Delete請求 http://127.0.0.1/v1/user/{uid} 提交內容uid,刪除用戶信息。
// @Title Delete
// @Description delete the user
// @Param uid path string true "The uid you want to delete"
// @Success 200 {string} delete success!
// @Failure 403 uid is empty
// @router /:uid [delete]
func (u *UserController) Delete() {
uid := u.GetString(":uid")
models.DeleteUser(uid)
u.Data["json"] = "delete success!"
u.ServeJSON()
}
其他相關設計原則可以參照上面內容。
3.3、生成自動化文檔
-
配置文件設置
EnableDocs=true
-
運行啟動命令
$ bee run -gendoc=true -downdoc=true
-gendoc=true
標識自動化的build文檔,-downdoc=true
自動下載swagger文檔查看器 -
運行瀏覽器查看接口
4、注意事項
- route.go注解路由運行是通過CommentRouterPath解析的,會在同文件下生成commentsRouter_controllers.go文件,但需要注意工程必須在GOPATH路徑下,不然無法生成,也會無法匹配路由。
- CORS問題
解決辦法:在main.go中將swagger集成到應用中
if beego.BConfig.RunMode == "dev" {
beego.BConfig.WebConfig.DirectoryIndex = true
beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
}