binding 绑定
Gin 绑定是一个很棒的反序列化库。它支持开箱即用的 JSON、XML、查询参数等,并带有内置的验证框架。
image.pngGin 绑定用于将 JSON、XML、路径参数、表单数据等序列化为结构和映射。它还具有具有复杂验证的内置验证框架。
Gin 通过提供结构标签支持各种格式。例如,标记用于序列化路径参数:
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
type Body struct {
// json tag to de-serialize json body
Name string `json:"name"`
}
func main() {
engine:=gin.New()
engine.POST("/test", func(context *gin.Context) {
body:=Body{}
// using BindJson method to serialize body with struct
if err:=context.BindJSON(&body);err!=nil{
context.AbortWithError(http.StatusBadRequest,err)
return
}
fmt.Println(body)
context.JSON(http.StatusAccepted,&body)
})
engine.Run(":3000")
}
BindJSON 读取正文缓冲区以将其反序列化为结构。 不能在同一上下文中调用两次,因为它会刷新正文缓冲区。
如果要将正文反序列化为两个不同的结构,请使用 复制正文缓冲区并将其添加到上下文中。ShouldBindBodyWith.
if err:=context.ShouldBindBodyWith(&body,binding.JSON);err!=nil{
context.AbortWithError(http.StatusBadRequest,err)
return
}
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
// path paramter with name details will mapped to Details
type URI struct {
Details string `json:"name" uri:"details"`
}
func main() {
engine:=gin.New()
// adding path params to router
engine.GET("/test/:details", func(context *gin.Context) {
uri:=URI{}
// binding to URI
if err:=context.BindUri(&uri);err!=nil{
context.AbortWithError(http.StatusBadRequest,err)
return
}
fmt.Println(uri)
context.JSON(http.StatusAccepted,&uri)
})
engine.Run(":3000")
}
使用
Gin 在内部使用验证器包进行验证。此包验证器提供了一组广泛的内置验证,包括 、类型验证和字符串验证。required
验证通过结构标记添加到结构中:binding
type URI struct {
Details string `json:"name" uri:"details" binding:"required"`
}
验证包包含len,max,min等复杂验证。
在处理联系人详细信息时,我们通常必须在 Web 应用程序后端中验证电话号码、电子邮件地址和国家/地区代码。请看下面的示例结构:
type Body struct {
FirstName string `json:"firstName" binding:"required"`
LastName string `json:"lastName" binding:"required"`
Email string `json:"email" binding:"required,email"`
Phone string `json:"phone" binding:"required,e164"`
CountryCode string `json:"countryCode" binding:"required,iso3166_1_alpha2"`
}
上述结构标记使用通用正则表达式验证电子邮件、使用国际 E.164标准的电话和采用[ ISO-3166-1]双字母标准的国家/地区代码。例如,它接受绑定过程的以下示例 JSON 有效qing:
{
"firstName": "John",
"lastName": "Mark",
"email": "jmark@example.com",
"phone": "+11234567890",
"countryCode": "US"
}
验证器包还提供邮政编码验证支持。
type Body struct {
PostCode string `json:"postCode" binding:"required,postcode_iso3166_alpha2=GB"`
}
验证错误处理
我们使用函数将 HTTP 错误代码发送回客户端,但没有发送有意义的错误消息。
因此,我们可以通过发送有意义的验证错误消息作为 JSON 输出
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
type Body struct {
Price uint `json:"price" binding:"required,gte=10,lte=1000"`
}
func main() {
engine:=gin.New()
engine.POST("/test", func(context *gin.Context) {
body:=Body{}
if err:=context.ShouldBindJSON(&body);err!=nil{
context.AbortWithStatusJSON(http.StatusBadRequest,
gin.H{
"error": "VALIDATEERR-1",
"message": "Invalid inputs. Please check your inputs"})
return
}
context.JSON(http.StatusAccepted,&body)
})
engine.Run(":3000")
}
现在,上面的代码使用该函数并向客户端返回唯一的错误代码和消息,以便客户端可以向用户显示有意义的错误消息。
现在,我们有了基于验证标记名称的清晰而有意义的错误消息。
package main
import (
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"net/http"
"errors"
)
type Body struct {
Product string `json:"product" binding:"required,alpha"`
Price uint `json:"price" binding:"required,gte=10,lte=1000"`
}
type ErrorMsg struct {
Field string `json:"field"`
Message string `json:"message"`
}
func getErrorMsg(fe validator.FieldError) string {
switch fe.Tag() {
case "required":
return "This field is required"
case "lte":
return "Should be less than " + fe.Param()
case "gte":
return "Should be greater than " + fe.Param()
}
return "Unknown error"
}
func main() {
engine:=gin.New()
engine.POST("/test", func(context *gin.Context) {
body:=Body{}
if err:=context.ShouldBindJSON(&body);err!=nil{
var ve validator.ValidationErrors
if errors.As(err, &ve) {
out := make([]ErrorMsg, len(ve))
for i, fe := range ve {
out[i] = ErrorMsg{fe.Field(), getErrorMsg(fe)}
}
context.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errors": out})
}
return
}
context.JSON(http.StatusAccepted,&body)
})
engine.Run(":3000")
}
自定义绑定
若要创建新绑定,必须向执行验证的函数注册验证。
// getting the validation engine and type casting it.
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
// registering validation for nontoneof
v.RegisterValidation("notoneof", func(fl validator.FieldLevel) bool {
// split values using ` `. eg. notoneof=bob rob job
match:=strings.Split(fl.Param()," ")
// convert field value to string
value:=fl.Field().String()
for _,s:=range match {
// match value with struct filed tag
if s==value {
return false
}
}
return true
})
}
您可以使用用于添加自定义验证程序的包访问验证引擎。变量将导出。 提供返回验证引擎的方法。
网友评论