1、安装Beego
$export GO111MODULE=on
$export GOPROXY=https://goproxy.io
$$ 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
运行命令
此处需要注意的是,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
- 运行启动命令
-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"
}