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 分割,五个分别表示的含义如下

    1. 参数名
    2. 参数类型,可以有的值是 formData、query、path、body、header,formData 表示是 post 请求的数据,query 表示带在 url 之后的参数,path 表示请求路径上得参数,header 表示带在 header 信息中得参数,body表示是一个raw数据请求,比如结构体的方式传递。
    3. 参数类型
    4. 是否必须
    5. 注释
  • @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文档查看器

  • 运行浏览器查看接口

    http://127.0.0.1/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"
	}
posted on 2021-02-08 23:33  Code2020  阅读(339)  评论(0编辑  收藏  举报