结合自定义 tag 实现 validate

PPG007 ... 2022-5-6 Less than 1 minute

# 结合自定义 tag 实现 validate

首先定义下面这样一个请求:

message DemoRequest{
  string id = 1; // @gotags: valid:"required,objectId"
  string status = 2; // @gotags: valid:"in(succeed|failed|processing),required"
  repeated string ids = 3; // @gotags: valid:"required,objectIdList"
  bool containDeleted = 4;
  int64 option = 5;
}
1
2
3
4
5
6
7

这里我们使用一个 govalidator (opens new window) 库:

go get github.com/asaskevich/govalidator
1

这个库本身具有一些内置的规则,可以在文档中找到,这里我们实现自定义验证,调用 govalidator.CustomTypeTagMap.Set 方法可以自定义验证:

func init() {
	// govalidator.TagMap["objectId"] = govalidator.Validator(func(str string) bool {
	// 	_, err := primitive.ObjectIDFromHex(str)
	// 	return err == nil
	// })

	govalidator.CustomTypeTagMap.Set("objectId", func(i, o interface{}) bool {
		s := cast.ToString(i)
		_, err := primitive.ObjectIDFromHex(s)
		return err == nil
	})

	govalidator.CustomTypeTagMap.Set("objectIdList", func(i, o interface{}) bool {
		strs := cast.ToStringSlice(i)
		for _, str := range strs {
			_, err := primitive.ObjectIDFromHex(str)
			if err != nil {
				return false
			}
		}
		return true
	})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

Tips

注释中的方法也可以用来自定义规则,但是只适用于单一字符串验证,如果是数组或者其他类型还是不够灵活。

接下来我们在接口实现中调用验证方法验证请求即可:

func (ValidatorService) Demo(ctx context.Context, req *proto.DemoRequest) (*proto.EmptyResponse, error) {
	if _, err := govalidator.ValidateStruct(req); err != nil {
		return nil, err
	}
	return &proto.EmptyResponse{}, nil
}
1
2
3
4
5
6