• 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"
    	}
  • 相关阅读:
    ssh加密访问
    protobuf java学习
    Errors occurred while updating the change sets for SVNStatusSubscriber org.apache.subversion.javahl.
    eclipse导入svn中的maven工程项目
    Archive for required library xx cannot be read or is not a valid ZIP file
    oracle9i 精简版客户端界面没有显示实例名
    mybatis3 sqlsession
    RabbitMQ学习之:(一)初识、概念及心得
    mybatis expected at least 1 bean which qualifies as autowire candidate for this dependency
    mysql 5.6.20 数据库中文乱码解决方法
  • 原文地址:https://www.cnblogs.com/cxy2020/p/14391516.html
Copyright © 2020-2023  润新知