AdSense

網頁

2022/5/20

Golang go-playground/validator bool required驗證失敗

Go 使用go-playground/validator驗證struct的bool欄位required時,設定值false時驗證失敗。


例如下面Employee.Deleted設為false,加上validate tag required驗證時會出現錯誤:

Key: 'Employee.Deleted' Error:Field validation for 'Deleted' failed on the 'required' tag

main.go

package main

import (
    "fmt"

    validator "github.com/go-playground/validator/v10"
)

type Employee struct {
    Id      int    `validate:"required"`
    Name    string `validate:"required"`
    Deleted bool   `validate:"required"`
}

func main() {
    emp := Employee{
        Id:      1,
        Name:    "John",
        Deleted: false,
    }
    err := validator.New().Struct(emp)
    if err != nil {
        fmt.Println(err)
    }
}

原因出在required對於基本型別的欄位是檢查值是否為非零值/非預設值(check field's value is non-zero/non-default value),而非字面意義上檢查值是否存在(因為基本型別欄位不可能是nil)。也就是說,當欄位是基本型別且值為零值(預設值)則驗證失敗。

Employee.Deleted為基本型別bool,零值為false,所以當值為false時與零值相同,則required驗證失敗。

查看可能的原始碼如下:

baked_in.go#L1499

// hasValue is the validation function for validating if the current field's value is not the default static value.
func hasValue(fl FieldLevel) bool {
    field := fl.Field()
    switch field.Kind() {
    case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
        return !field.IsNil()
    default:
        if fl.(*validate).fldIsPointer && field.Interface() != nil {
            return true
        }
        return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface() // check if field's value does not equal to zero value
    }
}

在最後回傳的判斷field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface()意思即為「欄位值是否為非零值」。


至於pointer欄位required才確實是驗證是否存在(是否為nil)。例如下面把Deleted欄位改為pointer則通過驗證。

main.go

package main

import (
    "fmt"

    validator "github.com/go-playground/validator/v10"
)

type Employee struct {
    Id      int    `validate:"required"`
    Name    string `validate:"required"`
    Deleted *bool  `validate:"required"`
}

func main() {
    deleted := false

    emp := Employee{
        Id:      1,
        Name:    "John",
        Deleted: &deleted,
    }
    err := validator.New().Struct(emp)
    if err != nil {
        fmt.Println(err)
    }
}

沒有留言:

AdSense