golang框架gin中的绑定

binding 绑定

Gin 绑定是一个很棒的反序列化库。它支持开箱即用的 JSON、XML、查询参数等,并带有内置的验证框架。

Gin 绑定用于将 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": "[email protected]",
   "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
   })
}

您可以使用用于添加自定义验证程序的包访问验证引擎。变量将导出。 提供返回验证引擎的方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章