Gin 模型绑定验证
同其它的框架有点不一样,Go中的web框架模型绑定,更多的是基于结构体标签。但总体流程还是一致,即后端对来自请求的各种数据类型进行验证,然后抛出相应的错误信息。Gin框架默认使用的是结构体验证器,其核心接口
StructValidator
只需关注两个,即数据验证和验证错误消息的返回,简单明了。
绑定
gin/binding
内置模型绑定实现,将请求数据提取到合适的绑定器
Gin 主要提供了两组绑定方法Must bind
与 Should bind
。
前者使用框架自带的处理机制,基本上验证不通过,就会被终止或抛出特定的错误页面。
后者存在绑定错误,这个错误会被返回, 需要开发者去处理相应的请求和错误,这样具有更大的灵活性。
Gin 框架本身已经实现了多种绑定,通常用来绑定来自请求数据,有不同的结构体实例与之对应。其实现的绑定有 JSON,
XML, Form,Query,FormPost,FormMultipart,ProtoBuf,MsgPack,YAML,Uri
,显然 Query是对查询字符串的绑定。
验证
validator.v8
验证器包,主要是解决验证规则的解析。实现了基于结构体值验证,及基于标签的单字段断言。针对内嵌结构体,也提供了跨字段和跨结构体验证,可处理任何类型的映射和数组。通常的做法是,验证后,提供本地的错误类型实例。
示例中的 gtfield
通用字段验证标签,而自定义的验证规则bookabledate,是对日期过滤。基本规则是确保出时间在进时间之后,且这两个时间都在系统当前时间(即未来发生)之后,否则报错。
流程
- 定义数据模型结构体
- 确定验证规则,包括跨字段验证
- 将请求数据模型使用合理的绑定器
- 处理绑定消息结果,决定错误消息是否渲染页面及视图
代码
下述代码对同一数据模型使用了多组标签,如 form,time_format,binding
,这样可以在同一对象上实现不同的效果展示 。binding
标签是在绑定过程中进行的验证,form
标签从请求的字段数据,time_format
标签的时间格式模板
package main
import (
"net/http"
"reflect"
"time"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"gopkg.in/go-playground/validator.v8"
)
// Booking 包含绑定和验证规则
type Booking struct {
CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2019-01-02"`
CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2019-01-02"`
}
// 自定义验证规则断言
func bookableDate(
v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value,
field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string,
) bool {
if date, ok := field.Interface().(time.Time); ok {
today := time.Now()
if today.After(date) {
return false
}
}
return true
}
func main() {
route := gin.Default()
// 注册验证
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
v.RegisterValidation("bookabledate", bookableDate)
}
route.GET("/bookable", getBookable)
route.Run(":8085")
}
func getBookable(c *gin.Context) {
var b Booking
// 数据模型绑定查询字符串验证
if err := c.ShouldBindWith(&b, binding.Query); err == nil {
c.JSON(http.StatusOK, gin.H{"message": "Booking dates are valid!"})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
}
测试
假定当前时间是 2019-11-10,根据自定义的验证规则 bookabledate
, 那么进出时间必须在该时间之后,否则不通过,效果如下
$ curl "localhost:8085/bookable?check_in=2019-11-11&check_out=2019-11-17"
{"message":"Booking dates are valid!"}
$ curl "localhost:8085/bookable?check_in=2019-03-08&check_out=2019-03-09"
{"error":"Key: 'Booking.CheckIn' Error:Field validation for 'CheckIn' failed on the 'bookabledate' tag"}
补充
- 多使用工具,window用vscode,linux环境下用vim-go 使用代码补全,溯源定义,利于快速的定位使用。像结构体标签vim-go 可用命令
:GoAddTags
快速让生成,会节省不少时间 - 测试简单的建议用
iehttp, nc
等命令行工具,简单不用写表单,表头前者天生支持json。至于Curl 工具虽然很强大,但对人并不是很友好。 - 专门的api接口测试,可用 postman 结合脚本自动化测试,并持久化测试请求,不必每次重新来过。
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: