validator icon indicating copy to clipboard operation
validator copied to clipboard

When the validation field does not exist

Open how2j-coder opened this issue 9 months ago • 3 comments

struct

type Request struct {
	Name  string `json:"name" validate:"optional_not_empty"`
	Email string `json:"email"`
}

How Customize one optional_not_empty to achieve the following results?

cases

testCases := []Request{
	{ Email: ""},         // The Name field is not inpassed, and the verification is passed
	{Name: "John", Email: ""},     // Name is passed in and the verification passes
        {Name: "", Email: ""},     // Name is passed in, but the value is blank and the verification fails
}

how2j-coder avatar Mar 13 '25 09:03 how2j-coder

Interesting scenario...
I'd love to see solutions from our community! Personally, I would create a custom validator for this case.

nodivbyzero avatar Mar 17 '25 20:03 nodivbyzero

It's possible to do

type Request struct {
	Name  *string `json:"name" validate:"omitempty,gt=0"`
	Email string  `json:"email"`
}

I am not sure if there is any other way how to do it. If you have to separate logic for not exist and null value, sadly with go we can do only this or using something like sql.Null types.

zemzale avatar Mar 19 '25 10:03 zemzale

@nodivbyzero Hello, I can only tell if I have this field in my struct by the address right now, but I don't feel good about that, It's like this

func validateOptionalNotEmpty(fl valid.FieldLevel) bool {
	// Gets the value of the field 获取字段的值
	field := fl.Field()
	if field.Kind() == reflect.Ptr && field.IsNil() {
		return true
	}

	// If the field is passed in, check if its value is empty 如果字段传入了,则检查其值是否为空
	switch field.Kind() {
	case reflect.String:
		return field.String() != ""
	case reflect.Slice, reflect.Map, reflect.Array:
		return field.Len() > 0
	case reflect.Ptr, reflect.Interface:
		return !field.IsNil()
	default:
		return true // Other types pass by default 其他类型默认通过
	}
}
......
func (v *CustomValidator) lazyInit() {
	v.Once.Do(func() {
		v.Validate = valid.New()
		v.Validate.SetTagName("binding")

		// Register a custom validation rule 注册自定义校验规则
		// optional_not_empty - The Null Test field type should be set to the pointer type 空效验 字段类型要设置为指针类型
                // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
		_ = v.Validate.RegisterValidation("optional_not_empty", validateOptionalNotEmpty, true)
	})
}

With RegisterValidation, I can get the Form Struct, which is the Struct I created, but how can I get the JSON data that was passed in for the request?

example:

this is request data:

{
  "role_name": "ordinary",
  "remark": "user role",
  "test": "test filed"
}

this my struct:

type UpdateRoleReq struct {
	RoleName string `json:"role_name" binding:""`
	Remark string `json:"remark" binding:""`
}

got my original request data via validateOptionalNotEmpty:

func validateOptionalNotEmpty(fl valid.FieldLevel, rawData interface{}) bool  {
  	print(rawData)
        // print:
	//	{
	//		"role_name": "ordinary",
	//		"remark": "user role",
	//		"test": "test filed"
	//	}
     

}

how2j-coder avatar Apr 25 '25 15:04 how2j-coder