相信后端开发同学都写过API文档,如果你只开发API接口而不写文档会估计会被喷,而且写文档确实是个好习惯。但是写文档这个事确实挺痛苦的,之前我的做法是在内部开发人员内部约定一个markdown模板来填写,类似api.md这种格式,每个接口都会有多个字段(URL,Method,Params)来说明。
同时,再结合postman这种工具,在完成接口自测的同时,将自测过程中的json参数或query参数等信息写到上述文档中;在这个过程中需要自己构建参数以及相关字段的说明,比较的繁琐。所以,希望能有工具能自动将代码中的对象或注释信息生成API文档。本文接下来将介绍两个工具来解决上述中的问题:
Swagger
Swagger是一个简单但功能强大的API表达工具。它具有地球上最大的API工具生态系统,数以千计的开发人员,使用几乎所有的现代编程语言,都在支持和使用Swagger。使用Swagger生成API,我们可以得到交互式文档,自动生成代码的SDK以及API的发现特性等。
swaggo
swaggo是一个用于将golang注解自动转换为Swagger 2.0文档的工具。
从上面的介绍中可知,结合Swagger和swaggo这两个工具,我们可以做到:
本节内容将通过一个gin示例项目来演示如何使用swaggo来构建我们的API文档。为什么使用gin这个库?因为我们实际项目中使用的就是gin,比较熟悉哈。当然,swaggo支持多个web框架:
下面我们进入正题(如果你还不熟悉go环境、项目构建等相关知识点,请先阅读文档How to Write Go Code):
首先,请安装swag
命令行工具:
$ go get -u github.com/swaggo/swag/cmd/swag
创建一个gin示例项目,整个项目的结构如下图所示:
在示例项目会创建用户(user)的增删改查接口用于说明swaggo的使用方法; 其中,main.go代码如下所示:
// @title swaggo demo
// @version 1.0
// @description swaggo demo
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host 127.0.0.1:8080
// @BasePath /api/v1
func main() {
r := gin.Default()
r.GET("api/v1/user/:id", handler.HandleGetUser)
r.GET("api/v1/users", handler.HandleGetUsers)
r.POST("api/v1/user", handler.HandlePostUser)
r.PUT("api/v1/user", handler.HandlePutUser)
r.DELETE("api/v1/user/:id", handler.HanleDeleteUser)
if err := r.Run(); err != nil {
fmt.Printf("Run err: %v", err)
}
}
main
函数上的注解会生成通用API信息(General API Info),其中@title
,@version
和@license.name是必须要填的,否则下面的步骤会失败;而
@host和
@BasePath`这两个注解也非常重要,如果你想在文档页面测试你的接口的话;swaggo还支持其他很多General API Info 注解。
然后,在main.go
文件所在目录下执行命令swag init
,执行命令后会在当前目前创建docs
目录,其包含三个文件:
其中,docs.go
需要导入到main.go
中,如下所示:
import (
"fmt"
_ "github.com/chowxiaojun/go-demos/swaggo-demo/docs"
"github.com/chowxiaojun/go-demos/swaggo-demo/handler"
"github.com/gin-gonic/gin"
)
为什么要导入这个文件呢?我们可以看下docs.go
这个文件:
func init() {
swag.Register(swag.Name, &s{})
}
如上代码所示,该文件中有一个init
函数,该函数会在main
函数之前执行,它的作用是注册了一个swagger,除此之外还有doc
变量存储我们API的相关信息,后续在生成swagger UI
形式的API文档页面时会需要用到。下面我们可以在main
函数中再加一条路由:
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
,
运行main.go
,在浏览器中输入地址http://127.0.0.1:8080/swagger/index.html
。此时ginSwagger.WrapHandler
就会去调用前面注册的swagger
,生成下图中的页面,你会发现上面我们写的注解信息都已经显示在页面上了。
接下来我们来看下怎么生成一个API相关的信息,以HandleGetUser
和HandlePostUser
API接口为例,详见user_handler.go和user.go这两个文件:
// @Summary Get a User
// @Description get User by ID
// @Tags User
// @Produce json
// @Param id path string true "User ID"
// @Success 200 {object} model.GetUserRsp
// @Failure 400 {object} model.GetUserRsp
// @Router /user/{id} [get]
func HandleGetUser(c *gin.Context) {
}
// @Summary Create a User
// @Description Create a User
// @Tags User
// @Accept json
// @Produce json
// @Param user body model.User true "User"
// @Success 200 {object} model.CommonRsp
// @Failure 400 {object} model.CommonRsp
// @Router /user [post]
func HandlePostUser(c *gin.Context) {
}
type CommonRsp struct {
ErrorCode int32 `json:"error_code" example:"0"`
ErrorMsg string `json:"error_msg" example:"success"`
}
type User struct {
ID string `json:"id" example:"10001"`
Name string `json:"name" example:"user name"`
Address string `json:"address" example:"user address"`
}
type GetUserRsp struct {
CommonRsp
Users []User `json:"users"`
}
重新再目录下执行命令swag init
,再次运行main.go
,我们可以看到以下页面:
在上图中,已经标注了具体注解对应页面上的信息:
上述图片中@Param是一个body参数,对应我们代码中定义的Model信息以及对应的JSON示例,再通过页面中的Try it out功能,我们可以直接在页面上调用我们的接口完成自测。swaggo还支持很多的API注解,请查看API Operation。
本文通过一个实际的项目介绍了swagger和swaggo的概念和使用方式,大家应该有了一个初步的了解;如果大家感兴趣的话,可以在项目中进行实践。最后,再说下整个使用下来的感受:第一,它们确实解决了我们的痛点;第二,更重的是——在实践过程中学到如何设计一个好的RESTful API接口。
除此之外,还需要注意一个问题:就是在生产环境中不能将这个文档暴露出去,这个可以通过很多方式来解决,在这里也不再赘述。
下面是一些推荐阅读的链接,大家可以进一步进行阅读:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。