本章节我们将使用固定的数据格式返回结果,无论路由函数执行成功还是失败,我们以json
格式返回结果给调用端。
返回格式定义
我们定义一个统一的数据结构:
type Response struct {
Message string `json:"message" dc:"消息提示"`
Data interface{} `json:"data" dc:"执行结果"`
}
由于我们需要返回json
数据格式,因此我们给每个字段都加上json
标签。
接口数据结构
type HelloReq struct {
g.Meta `path:"/" method:"get"`
Name string `v:"required" json:"name" dc:"姓名"`
Age int `v:"required" json:"age" dc:"年龄"`
}
type HelloRes struct {
Content string `json:"content" dc:"返回结果"`
}
- 我们给
HelloRes
增加了一个Content
属性,用于路由函数返回具体的数据。 - 由于需要通过
json
数据格式返回数据,因此所有的属性字段均增加json
标签。
路由回调函数
type Hello struct{}
func (Hello) Say(ctx context.Context, req *HelloReq) (res *HelloRes, err error) {
res = &HelloRes{
Content: fmt.Sprintf(
"Hello %s! Your Age is %d",
req.Name,
req.Age,
),
}
return
}
我们这里通过HelloRes
返回数据结构返回执行结果,而不是像前面的示例那样通过g.RequestFromCtx(ctx)
获取原始的请求对象直接Write
结果。
中间件定义
func Middleware(r *ghttp.Request) {
r.Middleware.Next()
var (
msg string
res = r.GetHandlerResponse()
err = r.GetError()
)
if err != nil {
msg = err.Error()
} else {
msg = "OK"
}
r.Response.WriteJson(Response{
Message: msg,
Data: res,
})
}
在该中间件中:
- 通过
r.GetHandlerResponse()
方法获取路由回调函数的执行结果,即路由回调函数返回的第一个结果参数*HelloRes
。 - 通过
r.GetError()
获取路由回调函数的执行状态,即路由回调函数返回的第二个结果参数error
,如果该结果不为nil
,表示该回调函数执行产生了错误。 - 通过
r.Response.WriteJson
将结果整合到统一的返回数据结构Response
,并编码为json
格式返回给调用端。
完整示例代码
main.go
package main
import (
"context"
"fmt"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
type Response struct {
Message string `json:"message" dc:"消息提示"`
Data interface{} `json:"data" dc:"执行结果"`
}
type HelloReq struct {
g.Meta `path:"/" method:"get"`
Name string `v:"required" json:"name" dc:"姓名"`
Age int `v:"required" json:"age" dc:"年龄"`
}
type HelloRes struct {
Content string `json:"content" dc:"返回结果"`
}
type Hello struct{}
func (Hello) Say(ctx context.Context, req *HelloReq) (res *HelloRes, err error) {
res = &HelloRes{
Content: fmt.Sprintf(
"Hello %s! Your Age is %d",
req.Name,
req.Age,
),
}
return
}
func Middleware(r *ghttp.Request) {
r.Middleware.Next()
var (
msg string
res = r.GetHandlerResponse()
err = r.GetError()
)
if err != nil {
msg = err.Error()
} else {
msg = "OK"
}
r.Response.WriteJson(Response{
Message: msg,
Data: res,
})
}
func main() {
s := g.Server()
s.Group("/", func(group *ghttp.RouterGroup) {
group.Middleware(Middleware)
group.Bind(
new(Hello),
)
})
s.SetPort(8000)
s.Run()
}
该示例中的所有代码我们已经做过了介绍,我们直接执行即可。
执行结果
运行后,我们访问 http://127.0.0.1:8000/?name=john&age=18 可以看到,页面输出结果符合预期。
我们尝试一下错误的参数请求 http://127.0.0.1:8000/ 可以看到,页面输出结果也同样符合预期。
学习小结
在本章节中,我们学会了使用常用的json
格式对接口进行统一的数据格式封装,这在有着成百上千接口的业务项目中是非常有必要的。
可以看到,我们已经将参数完整地进行了结构化,结构中带有详细的输入输出参数描述、类型定义甚至数据校验规则, 那么我们能否基于这些信息自动化地生成接口文档呢?答案也是肯定的,我们将在下一章节介绍。