同其它的框架有點不一樣,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 協議》,轉載必須註明作者和本文連結