內置的驗證標簽
Gin通過集成go-playground/validator提供模型驗證功能,並提供了很多常用驗證規則可以滿足我們大部分的開發需求。我們通過一個例子看一下怎么使用這些驗證標簽。
type AddUserRequest struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"` // 登錄密碼
Nickname string `json:"nickname" binding:"required"` // 昵稱
Mobile string `json:"mobile"` // 手機號
Email string `json:"email" binding:"required,email"` // 郵箱地址
}
func AddUser(c *gin.Context) {
req := sysUser.AddUserRequest{}
if err := c.ShouldBind(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
...
c.String(http.StatusOK, "")
}
在Username字段上增加了binding:"required"標簽,代表gin會驗證參數為必填項,如果沒有為Username字段提供值ShouldBind返回的err中會包含相應的錯誤內容。Email字段增加了binding:"required,email"標簽,這是一個組合驗證,代表Email是必填項的同時還要是一個正確的郵箱格式的字符串。
下面例子可以看到在未通過模型驗證時,接口返回的錯誤信息。
請求:
{
"username":"",
"password":"123qwe",
"nickname": "昵稱",
"mobile": "13322323232",
"email": "",
"qq": "234123412312"
}
響應:
{
"error": "Key: 'AddUserRequest.Username' Error:Field validation for 'Username' failed on the 'required' tag\nKey: 'AddUserRequest.Email' Error:Field validation for 'Email' failed on the 'required' tag"
}
自定義驗證
有時候內置的驗證規則可能不能滿足業務需求,這樣就需要自定義驗證規則。大致兩個步驟,1.定義一個驗證方法。2.把這個方法注冊為驗證規則。
type Booking struct {
CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"`
CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"`
}
var bookableDate validator.Func = func(fl validator.FieldLevel) bool {
date, ok := fl.Field().Interface().(time.Time)
if 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)
}
...
}
這里添加了一個叫做bookabledate的驗證規則,驗證一下參數是否大於今天。使用RegisterValidation("bookabledate", bookableDate)方法注冊為驗證規則,並且在CheckIn字段上增加了binding:"required,bookabledate"標簽。如果驗證失敗會返回錯誤信息:
Key: 'Booking.CheckIn' Error:Field validation for 'CheckIn' failed on the 'bookabledate' tag"
自定義錯誤消息
目前錯誤消息還是英文的,對於國內用戶很不友好,接口報錯的時候基本不可能把這種錯誤消息返回給用戶看。go-playground/validator提供了錯誤信息的翻譯,至少先解決英文錯誤的問題。在項目下新增validator/init.go文件。
package validator
import (
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/locales/zh"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
zh_translations "github.com/go-playground/validator/v10/translations/zh"
)
var (
uni *ut.UniversalTranslator
validate *validator.Validate
trans ut.Translator
)
func init() {
translator := zh.New()
uni = ut.New(translator, translator)
trans, _ = uni.GetTranslator("zh")
validate := binding.Validator.Engine().(*validator.Validate)
_ = zh_translations.RegisterDefaultTranslations(validate, trans)
}
func Translate(err error) string {
var result string
errors := err.(validator.ValidationErrors)
for _, err := range errors {
result += err.Translate(trans) + ";"
}
return result
}
在handler中調用validator.Translate方法獲取錯誤消息的中文翻譯。
func AddUser(c *gin.Context) {
req := sysUser.AddUserRequest{}
if err := c.ShouldBind(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": validator.Translate(err)})
return
}
...
c.String(http.StatusOK, "")
}
這樣訪問接口時會看到中文的錯誤信息:
{
"error": "Username為必填字段;"
}