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
   })
}

您可以使用用於添加自定義驗證程序的包訪問驗證引擎。變量將導出。 提供返回驗證引擎的方法。

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