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
})
}
您可以使用用於添加自定義驗證程序的包訪問驗證引擎。變量將導出。 提供返回驗證引擎的方法。