func GetOneUser(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
decoder := json.NewDecoder(r.Body)
var param GetUserParam
err := decoder.Decode(¶m)
if err != nil {
WriteResponse(w, ErrorResponseCode, “request param is invalid, please check!”, nil)
return
}
// get user from db
user, err := models.GetOne(strconv.Itoa(param.Id))
if err != nil {
logrus.Warn(err)
WriteResponse(w, ErrorResponseCode, "failed", nil)
return
}
WriteResponse(w, SuccessResponseCode, "success", user) } 复制代码根据swagger文档规范,一个swagger文档首先要有swagger的版本和info信息。利用go-swagger只需要在声明package之前加上如下注释即可: // Package classification User API. // // The purpose of this service is to provide an application // that is using plain go code to define an API // // Host: localhost // Version: 0.0.1 // // swagger:meta package service 复制代码然后在项目根目录下使用swagger generate spec -o ./swagger.json命令生成swagger.json文件:
此命令会找到main.go入口文件,然后遍历所有源码文件,解析然后生成swagger.json文件
{
“swagger”: “2.0”,
“info”: {
“description”: “The purpose of this service is to provide an application\nthat is using plain go code to define an API”,
“title”: “User API.”,
“version”: “0.0.1”
},
“host”: “localhost”,
“paths”: {}
}
复制代码2.基本信息有了,然后就要有路由,请求,响应等,下面针对getOneUser接口编写swagger注释:
// swagger:parameters getSingleUser
type GetUserParam struct {
// an id of user info
//
// Required: true
// in: path
Id int json:"id"
}
func GetOneUser(w http.ResponseWriter, r *http.Request) {
// swagger:route GET /users/{id} users getSingleUser
//
// get a user by userID
//
// This will show a user info
//
// Responses:
// 200: UserResponse
decoder := json.NewDecoder(r.Body)
var param GetUserParam
err := decoder.Decode(¶m)
if err != nil {
WriteResponse(w, ErrorResponseCode, “request param is invalid, please check!”, nil)
return
}
// get user from db
user, err := models.GetOne(strconv.Itoa(param.Id))
if err != nil {
logrus.Warn(err)
WriteResponse(w, ErrorResponseCode, "failed", nil)
return
}
WriteResponse(w, SuccessResponseCode, "success", user) } 复制代码可以看到在GetUserParam结构体上面加了一行swagger:parameters getSingleUser的注释信息,这是声明接口的入参注释,结构体内部的几行注释指明了id这个参数必填,并且查询参数id是在url path中。详细用法,参考: swagger:params 在GetOneUser函数中:
然后再声明响应:
// User Info
//
// swagger:response UserResponse
type UserWapper struct {
// in: body
Body ResponseMessage
}
type ResponseMessage struct {
Code int json:"code"
Message string json:"message"
Data interface{} json:"data"
}
复制代码使用swagger:response语法声明返回值,其上两行是返回值的描述(我也不清楚,为啥描述信息要写在上面,欢迎解惑),详细用法,参考; swagger:response
然后浏览器访问localhost,查看swagger-editor界面,点击工具栏中的File->Impoprt File上传刚才生成的 swagger.json文件,就可以看到界面:
这样一个简单的api文档就生成了
3.怎么样?是不是很简单?可是又感觉那里不对,嗯,注释都写在代码里了,很不美观,而且不易维护。想一下go-swagger的原理是扫描目录下的所有go文件,解析注释信息。那么是不是可以把api注释都集中写在单个文件内,统一管理,免得分散在各个源码文件内。
新建一个doc.go文件,这里还有一个接口是UpdateUser,那么我们在doc.go文件中声明此接口的api注释。先看一下UpdateUser接口的代码:
func UpdateUser(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
// decode body data into user struct
decoder := json.NewDecoder(r.Body)
user := models.User{}
err := decoder.Decode(&user)
if err != nil {
WriteResponse(w, ErrorResponseCode, “user data is invalid, please check!”, nil)
return
}
// check if user exists
data, err := models.GetUserById(user.Id)
if err != nil {
logrus.Warn(err)
WriteResponse(w, ErrorResponseCode, "query user failed", nil)
return
}
if data.Id == 0 {
WriteResponse(w, ErrorResponseCode, "user not exists, no need to update", nil)
return
}
// update
_, err = models.Update(user)
if err != nil {
WriteResponse(w, ErrorResponseCode, "update user data failed, please try again!", nil)
return
}
WriteResponse(w, SuccessResponseCode, "update user data success!", nil) } 复制代码然后再doc.go文件中编写如下声明: package service
import “user.server/models”
// swagger:parameters UpdateUserResponseWrapper
type UpdateUserRequest struct {
// in: body
Body models.User
}
// Update User Info
//
// swagger:response UpdateUserResponseWrapper
type UpdateUserResponseWrapper struct {
// in: body
Body ResponseMessage
}
// swagger:route POST /users users UpdateUserResponseWrapper
//
// Update User
//
// This will update user info
//
// Responses:
// 200: UpdateUserResponseWrapper
复制代码这样就把api声明注释给抽离出来了,然后使用命令swagger generate spec -o ./swagger.json生成json文件,就可以看到结果:
很简单吧,参照文档编写几行注释,然后一个命令生成API文档。
// Success response
// swagger:response ok
type swaggScsResp struct {
// in:body
Body struct {
// HTTP status code 200 - OK
Code int `json:"code"`
}
}
对于错误响应,除了名称(和示例的情况下的 HTTP 代码注释)之外,它们中的大多数类似于彼此。尽管如此,你仍然应该为每一个错误的情况进行定义,以便把它们作为你的端点可能的响应:
// Error Forbidden
// swagger:response forbidden
type swaggErrForbidden struct {
// in:body
Body struct {
// HTTP status code 403 - Forbidden
Code int `json:"code"`
// Detailed error message
Message string `json:"message"`
}
}
data 中包含 model.Repository 的示例响应:
// HTTP status code 200 and repository model in data
// swagger:response repoResp
type swaggRepoResp struct {
// in:body
Body struct {
// HTTP status code 200/201
Code int `json:"code"`
// Repository model
Data model.Repository `json:"data"`
}
}
data 中包含 model.Repository 切片的示例响应:
// HTTP status code 200 and an array of repository models in data
// swagger:response reposResp
type swaggReposResp struct {
// in:body
Body struct {
// HTTP status code 200 - Status OK
Code int `json:"code"`
// Array of repository models
Data []model.Repository `json:"data"`
}
}
总之,这将足以生成您的 API 文档。您也应该向文档添加验证,但遵循本指南将帮助您开始。由于这主要是由我自己的经验组成,并且在某种程度上参考了 Gitea 的源代码,我将会听取关于如何改进这部分并相应更新的反馈。
brew tap go-swagger/go-swagger
brew install go-swagger
Linux
go get -u github.com/go-swagger/go-swagger/cmd/swagger
export PATH=$GOPATH/bin:$PATH
执行完了之后,你发现多了几个文件夹,其中 cmd 目录里面包含 main 函数,是整个程序的入口,restapi 文件夹下面包含协议相关代码,其中 configure_xxx.go 是需要特别关注的,你需要在这个文件里面实现你具体的业务逻辑
现在你就其实已经可以运行程序了,go run cmd/comment-like-server/main.go,在浏览器里面访问一下你的 api,会返回一个错误信息,告诉你 api 还没有实现,下面就来实现一下吧
_ "github.com/swaggo/gin-swagger/example/basic/docs" // docs is generated by Swag CLI, you have to import it.
)
并增加swagger访问路由
url := ginSwagger.URL("http://localhost:8080/swagger/doc.json") // The url pointing to API definition
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, url))
3、一些注解,编写各API handler方法注释(注解格式传送门)
1)main.go主程序文件注释:
// @title Golang Esign API
// @version 1.0
// @description Golang api of demo
// @termsOfService http://github.com
// @contact.name API Support
// @contact.url http://www.cnblogs.com
// @contact.email ×××@qq.com