Giter Site home page Giter Site logo

gookit / validate Goto Github PK

View Code? Open in Web Editor NEW
1.0K 21.0 116.0 744 KB

⚔ Go package for data validation and filtering. support Map, Struct, Form data. Go通用的数据验证与过滤库,使用简单,内置大部分常用验证、过滤器,支持自定义验证器、自定义消息、字段翻译。

Home Page: https://gookit.github.io/validate/

License: MIT License

Go 99.75% HTML 0.25%
validation validator filter govalidator validate verification

validate's Issues

能否请在文档中确认用法:可以为空,但有值必须满足条件。

有的时候,一个值是可以为空的,代表不更新。但是一旦有值,则希望这个值是满足后续条件的。能否请详细指教这样的场景用法?(比如,现在版本不加required,就是满足这种需求的,但是以文本的方式在README里面加以确认,应该可以解除部分像我这样的困惑吧。)

谢谢。

validate.Errors希望增加一个trans功能

在集成echo的发现的问题,最后单独实现了一个validate接口给echo,内部调用struct,最终给前端的时候,是error接口,强行转回validate.Errors类型,但是这个时候已经没办法重新格式化语种

希望增加多级校验规则

多级验证规则示例:

{
      "data": [
            {
                  name: xx,
                  id: xx,
                  rate: xx, 
             },
            {
                  name: xx,
                  id: xx,
                  rate: xx, 
             },
       ]
}

规则:
"data.*.name" =>"required|string|minLen:5",
"data.*.id" =>"required|int|min:1",
"data.*.rate" =>"required|float|count:100",   //合计为100, minCount:99最少99,maxCount:100.1最大100.1
required_unless:anotherfield,value,...
如果其它字段 _anotherfield_ 不等于任一值 _value_ ,则此验证字段必须存在且不为空。


required_with:foo,bar,...
在其他任一指定字段出现时,验证的字段才必须存在且不为空。


required_with_all:foo,bar,...
只有在其他指定字段全部出现时,验证的字段才必须存在且不为空。


required_without:foo,bar,...
在其他指定任一字段不出现时,验证的字段才必须存在且不为空。


required_without_all:foo,bar,...
只有在其他指定字段全部不出现时,验证的字段才必须存在且不为空。

starts_with:foo,bar,...
验证字段必须以给定值之一开头。

更多可参考规则验证器
https://learnku.com/docs/laravel/6.x/validation/5144#c58a91

TODO 请问有方法实现结构体的嵌套嘛

在使用protobuf的时候,起先定义了一个User,在User里面定义了字段和校验,然后在请求的message中直接message UserNewReq {User user = 1;},这时候好像没有去校验字段。

添加regex时报错,提示输入参数过多

v.StringRule("code", required|regex:\d{4,6})

panic: validate: the number of parameters given does not match the required. validator 'regex', want 2, given 3

goroutine 1 [running]:
validate.panicf(...)
	validate/helper.go:287
validate.(*funcMeta).checkArgNum(0xc0000c7dc0, 0x3, 0x13ab011, 0x5)
	validate/validators.go:198 +0x1b6
validate.(*Rule).valueValidate(0xc0001ee000, 0x13a874a, 0x4, 0x13a8e15, 0x6, 0x13a8301, 0x1331a60, 0xc0000bae30, 0xc0000f22c0, 0x0)
	validate/validate.go:166 +0x1c7
validate.(*Rule).Apply(0xc0001ee000, 0xc0000f22c0, 0x0)
	validate/validate.go:83 +0x6c0
validate.(*Validation).Validate(0xc0000f22c0, 0x0, 0x0, 0x0, 0xd)
	validate/validation.go:332 +0x10c

exit status 2

自定义规则时如何获取规则名后的参数

type Request struct{
      Name string `validate:"exists:user:name"`
}


v.AddValidator("exists", func(val interface{}) bool {
		return false
	})

v.AddValidator("exists", func(val interface{},args []interface) bool {
		return false
	})

上面两种方式,第一种获取不到参数,第二种提示只不是个slice。自定义时如何获取规则后的参数呢?

Some issue

  • If FromRequest func is called, the request body is nil.

  • Instance Validation struct every time?

type p struct  {
    Name string "validate:required"
}
type p2 struct  {
    Name2 string "validate:required"
}
p1 := p{Name: "name1"}
p2 := p{Name2: "name2"}
validate.Struct(p1)
validate.Struct(p2)

validate.Struct every time return new Validation.
Can instance once Validation?

regexp 无法匹配

类似这样的正则应该如何在 struct 中书写规则?

^(SLOTS|LIVE|SPORTS|LOTTERY)(,(SLOTS|LIVE|SPORTS|LOTTERY))*$

参数会用 | 分隔,跟踪得到匹配规则变为 ^(SLOTS

如果改为
^(SLOTS\|LIVE\|SPORTS\|LOTTERY)(,(SLOTS\|LIVE\|SPORTS\|LOTTERY))*$
则该条规则丢失

plus: 正则表达式如有 , 也会导致规则丢失

如果struct里面嵌套一个struct就验证不了了,请问有办法吗

如果struct里面嵌套一个struct就验证不了了,请问有办法吗

type AdminUserLoginRequest struct {
Localtime uint64 json:"localtime" binding:"required"
Data struct {
UserName string json:"username" validate:"required|string|CheckExists"
Password string json:"password" validate:"required|CheckPasswordIsEq"
} json:"data" binding:"required"
}

结构体定义错误信息后续的错误信息无法使用message tag

type RegisterRequest struct {
	Username string `json:"username" validate:"required" message:"请输入正确的用户名"`
	Password string `json:"password" validate:"required" message:"登录密码不能为空"`
	Confirm  string `json:"confirm"  validate:"required|eqField:password" message:"重复密码必须与登录密码一致"`
	Phone    string `json:"phone"    validate:"required|isCnMobile" message:"请填写正确格式的手机号码"`
	Code     string `json:"code"     validate:"required" message:"请填写正确格式的手机验证码"`
}

在Confirm定义了两个验证规则:required与eqField。
实际输出是:confirm value must be equal the field password

required好像不支持指针变量的校验.

我使用go-playground校验器的时候, 校验零值只需要定义指针就行了, 但是这里好像不行. 下面是我的demo例子.

package test

import (
	"fmt"
	"github.com/gookit/validate"
	_ "novel/bootstrap"
	"testing"
)


// UserForm struct
type UserDto struct {
	// Name     string    `validate:"required|minLen:7"`
	Name     string    `validate:"required"`
	Sex   	*bool	   `validate:"required"`
}


// Messages 您可以自定义验证器错误消息
func (ud UserDto) Messages() map[string]string {
	return validate.MS{
		"required": "oh! the {field} is required",
		"Name.required": "name 必填",
	}
}

func testValidate(ud *UserDto)  {
	// 创建 Validation 实例
	v := validate.Struct(ud)
	if !v.Validate() {
		fmt.Println(v.Errors)
	} else {
		fmt.Println("Success...")
	}
}

func TestMyValidator(t *testing.T)  {
	sex := true
	u := UserDto{
		// Name: "inhere",
		Name: "abc",
		Sex: &sex,
	}
	testValidate(&u)
	// 下面如果Sex不传或传nil, 会panic错误
	testValidate(&UserDto{
		Name: "abc",
		Sex: nil,
	})
}

请问该如何解决零值的校验问题呢?

能否有更明确的文档描述 contains/in 这些的用法?

相对而言,=, >, <, =>, <=, 这些应该都比较直观。isXXX,required,这些也都很简洁直观。

但有些就不那么直观,比如:

validate="contains=[1,2,‘3’]"
validate="contains=1,2,3|..."
validate="in=(1,2,3)"
validate="range =1-2"
validate="range =3,4"
validate="range =(5,6)"
validate="range =[7,8]"

似乎都有可能。很多细节都有赖于开发者最初决定选用的方式。
但实际上合理的方式通常只有一种。

如果文档里可以直接写清楚范例,比大量的文字描述要更加直观清楚很多。


我斗胆猜一下,等下去试试……
validate="in:0,1,2"
看看会不会报错(捂脸

int类型验证

package main

import "fmt"

import "github.com/gookit/validate"

func main() {
	m := map[string]interface{}{
		"name":  "inhere1",
		"age":   12.1234,
	}

	v := validate.Map(m)
        v.AddRule("age", "int")
        if v.Validate() { // validate ok
		fmt.Println(m)
	} else {
		fmt.Println(v.Errors)       // all error messages
		fmt.Println(v.Errors.One()) // returns a random error message text
	}
}

为什么上面的这个可以验证通过呀

验证图片失败!Failed to validate the image

我上传一个照片 / i upload a photo.

当我在BEEGO中获取文件 / when i get it in beego
f, _ , _ := this.GetFile(k)

并且创建一个validate规则 / and i create a validate rule
v.AddRule("thumbnail", "image")

控制台提示debug信息:thumbnail must be an uploaded image file
The console debug information: thumbnail must be an uploaded image file

有些验证字段不生效

使用方法

type SetProfileReq struct {
	Nickname string `json:"nickname" validate:"" filter:"trim"`
	Avatar   string `json:"avatar" validate:"required|url" filter:"trim"`
}

func checkSetProfileReq(ctx echo.Context, req *SetProfileReq) (*response.NO, error) {
	if err := ctx.Bind(req); err != nil {
		return response.NewNO(
			response.InvalidArgument,
			locale.Message(ctx, "invalid_argument"),
		), errors.Wrapf(err, "bind param err")
	}

	fmt.Println("bind:", req)

	if err := ctx.Validate(req); err != nil {
		return response.NewNO(
			response.InvalidArgument,
			locale.Message(ctx, "invalid_argument"),
		), errors.Wrapf(err, "validate param err")
	}

	fmt.Println("validated:", req)

	return nil, nil
}

// validate方法的实现
type Validate struct {
}

func (Validate) Validate(i interface{}) error {
	v := validate.Struct(i)
	if !v.Validate() {
		return v.Errors
	}
	return v.BindSafeData(i)
}

Avatar使用了两个规则,required和url。但是url规则不生效。
测试的结果

bind: &{123nickname111 1}
validated: &{123nickname111 1}

验证通过,没有校验url格式。
我换另一个规则,如required|ip,这样也是生效的。会检查ip格式。

版本信息

1.1.3

float64类型验证错误

float64类型验证报错

package main

import (
	"github.com/gookit/validate"
	"fmt"
)
type Fl struct {
	A float64 `validate:"float"`
}
func main() {
	fl := Fl{123}
	va := validate.Struct(fl)
	fmt.Println(va.Validate())
}
panic: reflect: Call using float64 as type string

goroutine 1 [running]:
reflect.Value.call(0x6d76e0, 0x74fc60, 0x13, 0x7392dd, 0x4, 0xc0420f1460, 0x1, 0x1, 0x738360, 0x6c71e0, ...)
	C:/setup/go/src/reflect/value.go:377 +0x1209
reflect.Value.Call(0x6d76e0, 0x74fc60, 0x13, 0xc0420f1460, 0x1, 0x1, 0x779b00, 0x6d76e0, 0xc042183cd8)
	C:/setup/go/src/reflect/value.go:308 +0xab
github.com/gookit/validate.callValidatorValue(0x6d76e0, 0x74fc60, 0x13, 0x6c71e0, 0xc042132830, 0x0, 0x0, 0x0, 0x6c71e0)
	E:/crm/src/github.com/gookit/validate/validate.go:467 +0x1c6
github.com/gookit/validate.callValidator(0xc0420be2c0, 0xc042066f80, 0x6ab245, 0x1, 0x6c71e0, 0xc042132830, 0x0, 0x0, 0x0, 0x68c7de)
	E:/crm/src/github.com/gookit/validate/validate.go:449 +0x214
github.com/gookit/validate.(*Rule).valueValidate(0xc042135400, 0x6ab245, 0x1, 0x739e1b, 0x7, 0x6c71e0, 0xc042132830, 0xc0420be2c0, 0x0)
	E:/crm/src/github.com/gookit/validate/validate.go:295 +0x184
github.com/gookit/validate.(*Rule).Apply(0xc042135400, 0xc0420be2c0, 0x0)
	E:/crm/src/github.com/gookit/validate/validate.go:188 +0x603
github.com/gookit/validate.(*Validation).Validate(0xc0420be2c0, 0x0, 0x0, 0x0, 0x0)
	E:/crm/src/github.com/gookit/validate/validation.go:399 +0x11e

validate: custom type check

type STATUS int32
var s1 STATUS = 1
func TestValidation_Enum(t *testing.T) {
	v := New(M{
		"age":     s1,
	})
	v.StringRules(MS{
		"age": "required|in:1,2,3,4",
	})

	v.Validate()

	fmt.Println(v.Errors)
}
age:
 age value must be in the enum [1 2 3 4]

奇怪的返回值,年龄最少18岁%!(EXTRA int64=18)

提交的数据是
age=10
www.xxx.com/test?age=10

结构体里定义的是
Age int form:"age" json:"age" validate:"required|int|min:18|max:150"``

自定义返回的信息是

`return validate.MS{

	"Age.min":"年龄最少18岁",
	"Age.max":"年龄最大150岁",
}

`

实际上返回的错误信息是
年龄最少18岁%!(EXTRA int64=18)
不知道为什么突然会冒出来 %!(EXTRA int64=18)
为什么会突然冒出来这样的?

json属性的值为数值类型,panic了

规则:
"cost_type": "required|number|min:1",

json数据

{
   "cost_type": 10 // 修改为 "10" 则不会panic
}
runtime/debug.Stack(0x2016ffd, 0x2, 0xc0000195c8)
	/usr/local/Cellar/go/1.13.4/libexec/src/runtime/debug/stack.go:24 +0x9d
git.liebaopay.com/INA_financial/rpc_services/app/srv/workflow/services.(*Workflow).CreateTask.func1(0xc00042e780)
	/app/go/rpc_services/app/srv/workflow/services/task.go:46 +0xde
panic(0x1e59a20, 0xc0002c2210)
	/usr/local/Cellar/go/1.13.4/libexec/src/runtime/panic.go:679 +0x1b2
github.com/gookit/validate.callValidator(0xc000470370, 0xc000367300, 0xc0004483d0, 0x9, 0x1dbc500, 0xc0004480f0, 0x0, 0x0, 0x0, 0x1)
	/Users/chenjiang/go/pkg/mod/github.com/gookit/[email protected]/validate.go:228 +0x11d3
github.com/gookit/validate.(*Rule).valueValidate(0xc000157f40, 0xc0004483d0, 0x9, 0x201e3b2, 0x8, 0x2016f01, 0x1dbc500, 0xc0004480f0, 0xc000470370, 0xc0002fa801)
	/Users/chenjiang/go/pkg/mod/github.com/gookit/[email protected]/validate.go:186 +0x17c
github.com/gookit/validate.(*Rule).Apply(0xc000157f40, 0xc000470370, 0x0)
	/Users/chenjiang/go/pkg/mod/github.com/gookit/[email protected]/validate.go:83 +0x6ba
github.com/gookit/validate.(*Validation).Validate(0xc000470370, 0x0, 0x0, 0x0, 0xc000470370)
	/Users/chenjiang/go/pkg/mod/github.com/gookit/[email protected]/validation.go:332 +0x109
git.liebaopay.com/INA_financial/rpc_services/app/srv/workflow/util/rule.Check(0xc000154000, 0x2f9, 0x300, 0x1, 0x300, 0x0)
	/app/go/rpc_services/app/srv/workflow/util/rule/rulevalidate.go:43 +0x3d6
git.liebaopay.com/INA_financial/rpc_services/app/srv/workflow/services.(*Workflow).CreateTask(0xc000019ed8, 0x22155e0, 0xc0000ba008, 0xc0000e0910, 0xc00042e780, 0x0, 0x0)
	/app/go/rpc_services/app/srv/workflow/services/task.go:109 +0xd2e
git.liebaopay.com/INA_financial/rpc_services/app/srv/workflow/services.TestAddTask(0xc000131500)
	/app/go/rpc_services/app/srv/workflow/services/task_test.go:109 +0x1b3
testing.tRunner(0xc000131500, 0x2073fd8)
	/usr/local/Cellar/go/1.13.4/libexec/src/testing/testing.go:909 +0xc9
created by testing.(*T).Run
	/usr/local/Cellar/go/1.13.4/libexec/src/testing/testing.go:960 +0x350
	{"srv_name": "workflow_run"}
code:fail message:"interface conversion: interface {} is float64, not string" 
--- PASS: TestAddTask (0.73s)

number 只能判断 字符串中的数值,希望可以增强一下
或者添加一个numeric表示数值类型,无论是字符串数值还是数值类
但不应该panic ?

内置过滤器字段是驼峰无效

如果用struct方式使用,且字段名字是大驼峰,过滤器无效。

type SmsReq struct {
	CountryCode string `json:"country_code" validate:"required" filter:"trim|lower"`
	Phone       string `json:"phone" validate:"required" filter:"trim"`
	Type        string `json:"type" validate:"required|in:register,forget_password,set_pay_password,reset_pay_password,reset_password" filter:"trim"`
}
CountryCode 不会过滤但是改为一个单词的时候就会

版本
1.1.1

怎么设置正则表达式验证

作者您好
看代码是有正则表达式验证的regexp
但是具体怎么使用可以给一个例子吗?
感激不尽

例如 Age字段只能为1-3位数字 \d{1-3}
在结构体里定义验证规则的时候,应该怎么定义呢?

bug: 场景验证

这个是正常的预期,名字不符合长度

image

如果是这样,带上场景,就都不验证了

image

版本信息

validate的版本是1.1.1
go version go1.12.6 darwin/amd64

当值为int 0时required会提示验证错误

type AddMenuRequest struct {
	ParentId  int64  `json:"parent_id"  validate:"required|uint" message:"required:父级ID不能为空|uint:父级ID参数异常"`
}

当字段必填并且可以为0时就不能这么使用验证了,它会告诉我这个字段的值为空。
我只能验证uint,再在别的地方另外去判断到底有没有传parent_id这个字段

uint 为 0 时无法验证最小值

结构体如下:

type Tag struct {
	ID   uint   `validate:"min:2"`
	Name string `validate:"required|maxLen:20"`
}

Tag.ID = 0 验证通过,有问题

Tag.ID = 1 验证不通过,这是对的

@inhere

正则表达不支持使用“|”语法吗?


import (
	"fmt"
	"github.com/gookit/validate"
)

func main() {
	m := map[string]interface{}{
		"name": "PCAP",
	}
	v := validate.Map(m)
	v.StringRule("name", "regex:^(PCAP|DOC)$")
	if v.Validate() { // validate ok
		fmt.Println("validate success")
	} else {
		fmt.Println(v.Errors)       // all error messages
		fmt.Println(v.Errors.One()) // returns a random error message text
	}
}

如何在Create和Update**用一套 验证规则

大佬又是我。。这次是在开发中遇到的问题,我现在是用验证规则绑定在了结构体的tag
这样创建是没有什么问题,但是在更新数据的时候会有问题,前端传递过来的更新数据 有些项不需要更新的话传的是空,还有些自定义的验证器是创建用的和更新的时候冲突的,这样一来数据的更新就没办法来验证。求教大佬有什么好的方式么?

How to apply filter via struct?

https://github.com/gookit/validate/blob/master/validation_test.go#L126 - this is a nice way to apply validators into specific struct property. Is there a way to apply filters at the same line?

I've tried:

type Whatever struct {
	Uno    string `validate:"required|lower|in:one,two,true" `             // --> validate: the validator 'lower' is not exists
	Dos    string `validate:"required|upper|enum:FOUR,FIVE,SIX" `          // --> validate: the validator 'upper' is not exists
	Tres   string `filter:"upper" validate:"required|in:ONE,TWO,THREE" `   // passing 'one' --> Tres value must be in the enum [ONE TWO THREE]
	Cuatro string `filter:"lower" validate:"required|enum:four,five,six" ` // passing 'SiX' --> Cuatro value must be in the enum [four five six]
}

but without success. Adding validation.FilterRule("Tres", "trim|upper") works, but it is somehow distant from those validation rules (within a struct). I would like to keep those together. Can you update the Readme. Or at least provide some examples in here?

自定义错误内容不生效

示例代码:

	m := map[string]interface{}{
		"title": "1",
	}
	v := validate.Map(m)
	v.StringRule("title", "in:2,3")
	v.AddMessages(map[string]string{
		"in":"自定义错误",
	})
	if !v.Validate() {
		fmt.Println(v.Errors.One())
	}

输出(没有输出自定义错误):

title value must be in the enum [2 3]

data_source.go 第 327 行的 Set() 方法

Set(field string, val interface{})

参数分别是 “Msg2”(string),“ping”(string)

在 355 行,newVal, err = convertType(val, srcKind, fv.Kind())
返回的 newVal 和 err 均为 nil

因为 err 为 nil
接下来的

if err != nil {
	return nil, err
}

没有生效

导致 361 行的fv.Set(reflect.ValueOf(newVal))接收的参数 newVal 以 nil 传入

这里直接 panic,而且也没有错误处理

请问,Set()方法有什么作用?为了解决刚才我遇到的这个问题,我让 set()方法直接返回了 参数中传入的 val

feat: 支持字段默认值

	type User struct {
		Name string `validate:"required|default:tom" filter:"trim|upper"`
		Age int `validate:"uint|default:23"`
	}

ptr type field not work as expected

// Test_validate_with_point 
// failed
//  Note: ptr field name expected works, but not actually
func Test_validate_with_point(t *testing.T) {
	type Foo struct {
		Name *string `validate:"in:henry,jim"`
	}
	name := "henry"
	valid := validate.New(&Foo{Name: &name})
	if !valid.Validate() {
		t.Log("err:", valid.Errors)
	}
}

// Test_validate_without_point 
// this tests will pass
func Test_validate_without_point(t *testing.T) {
	type Foo struct {
		Name string `validate:"in:henry,jim"`
	}
	name := "henry"
	valid := validate.New(&Foo{Name: name})
	if !valid.Validate() {
		t.Log("err:", valid.Errors)
	}
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.