結構體驗證
用gin框架的數據驗證,可以不用解析數據,減少if else,會簡潔許多。
- 處理請求方法
func structValidator(context *gin.Context) {
var person Person
if err := context.ShouldBind(&person); err != nil {
fmt.Println(err)
context.String(http.StatusBadRequest, "failed")
return
}
context.JSON(http.StatusOK, &person)
}
- 驗證結構體
type Person struct {
// 不能為空並且大於10
Age int `json:"age" form:"age" binding:"required,gt=10"`
Name string `json:"name" form:"name" binding:"required"`
Birthday time.Time `json:"birthday" form:"birthday" time_format:"2006-01-02 15:04:05" time_utc:"0"`
}
自定義驗證 V10版本
依賴:github.com/go-playground/validator/v10
type Person struct {
// 不能為空並且大於10
Age int `json:"age" form:"age" binding:"required,gt=10"`
// 2、在參數 binding 上使用自定義的校驗方法函數注冊時候的名稱
Name string `json:"name" form:"name" binding:"NotNullAndAdmin"`
Birthday time.Time `json:"birthday" form:"birthday" time_format:"2006-01-02"`
}
func NotNullAndAdmin(fl validator.FieldLevel) bool {
if value, ok := fl.Field().Interface().(string); ok {
// 字段不能為空,並且不等於 admin
return value != "" && !("admin" == value)
}
return false
}
func RegisterValidator() {
// 將我們自定義的校驗方法注冊到validator中
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
// 這里的 key 和 fn 可以不一樣最終在 struct 使用的是 key
v.RegisterValidation("NotNullAndAdmin", NotNullAndAdmin)
}
}
func main() {
// 注冊驗證器
blog.RegisterValidator()
}
自定義驗證器 V8版本
點擊查看代碼
package main
import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"gopkg.in/go-playground/validator.v8"
"net/http"
"reflect"
"time"
)
//binding 綁定一些驗證請求參數,自定義標簽bookabledate表示可預約的時期
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=CheckOut,bookabledate" time_format:"2006-01-02"`
}
//定義bookabledate標簽對應的驗證方法
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 date.Unix() > today.Unix() {
return true
}
}
return false
}
func main() {
route := gin.Default()
//將驗證方法注冊到驗證器中
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
v.RegisterValidation("bookabledate", bookableDate)
}
route.GET("/bookable", getBookable)
route.Run(":8080")
}
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()})
}
}
V10 版本示例2
func RegisterValidator() {
// 將我們自定義的校驗方法注冊到validator中
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
// 這里的 key 和 fn 可以不一樣最終在 struct 使用的是 key
v.RegisterValidation("NotNullAndAdmin", NotNullAndAdmin)
v.RegisterValidation("bookableDate", bookableDate)
}
}
type Booking struct {
// 定義一個預約的時間大於今天的時間
CheckIn time.Time `json:"check_in" binding:"required,bookableDate" time_format:"2006-01-02"`
// gtfield=CheckIn退出的時間大於預約的時間
CheckOut time.Time `json:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"`
}
func bookableDate(fl validator.FieldLevel) bool {
if v, ok := fl.Field().Interface().(time.Time); ok {
currentTime := time.Now().Unix()
if currentTime > v.Unix() {
return false
}
}
return true
}
請求參數:
{
"check_in": "2021-12-13T8:16:25Z", // UTC時區
"check_out": "2021-12-13T16:16:26+08:00" // 中國:東八時區
}