@@ -11,6 +11,12 @@ import (
11
11
"google.golang.org/grpc/status"
12
12
)
13
13
14
+ // The validateAller interface at protoc-gen-validate main branch.
15
+ // See https://github.com/envoyproxy/protoc-gen-validate/pull/468.
16
+ type validateAller interface {
17
+ ValidateAll () error
18
+ }
19
+
14
20
// The validate interface starting with protoc-gen-validate v0.6.0.
15
21
// See https://github.com/envoyproxy/protoc-gen-validate/pull/455.
16
22
type validator interface {
@@ -22,9 +28,25 @@ type validatorLegacy interface {
22
28
Validate () error
23
29
}
24
30
25
- // Calls the Validate function on a proto message using either the current or legacy interface if the Validate function
26
- // is present. If validation fails, the error is wrapped with `InvalidArgument` and returned.
27
- func validate (req interface {}) error {
31
+ func validate (req interface {}, all bool ) error {
32
+ if all {
33
+ switch v := req .(type ) {
34
+ case validateAller :
35
+ if err := v .ValidateAll (); err != nil {
36
+ return status .Error (codes .InvalidArgument , err .Error ())
37
+ }
38
+ case validator :
39
+ if err := v .Validate (true ); err != nil {
40
+ return status .Error (codes .InvalidArgument , err .Error ())
41
+ }
42
+ case validatorLegacy :
43
+ // Fallback to legacy validator
44
+ if err := v .Validate (); err != nil {
45
+ return status .Error (codes .InvalidArgument , err .Error ())
46
+ }
47
+ }
48
+ return nil
49
+ }
28
50
switch v := req .(type ) {
29
51
case validatorLegacy :
30
52
if err := v .Validate (); err != nil {
@@ -41,9 +63,13 @@ func validate(req interface{}) error {
41
63
// UnaryServerInterceptor returns a new unary server interceptor that validates incoming messages.
42
64
//
43
65
// Invalid messages will be rejected with `InvalidArgument` before reaching any userspace handlers.
44
- func UnaryServerInterceptor () grpc.UnaryServerInterceptor {
66
+ // If `all` is false, the interceptor returns first validation error. Otherwise the interceptor
67
+ // returns ALL validation error as a wrapped multi-error.
68
+ // Note that generated codes prior to protoc-gen-validate v0.6.0 do not provide an all-validation
69
+ // interface. In this case the interceptor fallbacks to legacy validation and `all` is ignored.
70
+ func UnaryServerInterceptor (all bool ) grpc.UnaryServerInterceptor {
45
71
return func (ctx context.Context , req interface {}, info * grpc.UnaryServerInfo , handler grpc.UnaryHandler ) (interface {}, error ) {
46
- if err := validate (req ); err != nil {
72
+ if err := validate (req , all ); err != nil {
47
73
return nil , err
48
74
}
49
75
return handler (ctx , req )
@@ -53,9 +79,13 @@ func UnaryServerInterceptor() grpc.UnaryServerInterceptor {
53
79
// UnaryClientInterceptor returns a new unary client interceptor that validates outgoing messages.
54
80
//
55
81
// Invalid messages will be rejected with `InvalidArgument` before sending the request to server.
56
- func UnaryClientInterceptor () grpc.UnaryClientInterceptor {
82
+ // If `all` is false, the interceptor returns first validation error. Otherwise the interceptor
83
+ // returns ALL validation error as a wrapped multi-error.
84
+ // Note that generated codes prior to protoc-gen-validate v0.6.0 do not provide an all-validation
85
+ // interface. In this case the interceptor fallbacks to legacy validation and `all` is ignored.
86
+ func UnaryClientInterceptor (all bool ) grpc.UnaryClientInterceptor {
57
87
return func (ctx context.Context , method string , req , reply interface {}, cc * grpc.ClientConn , invoker grpc.UnaryInvoker , opts ... grpc.CallOption ) error {
58
- if err := validate (req ); err != nil {
88
+ if err := validate (req , all ); err != nil {
59
89
return err
60
90
}
61
91
return invoker (ctx , method , req , reply , cc , opts ... )
@@ -64,26 +94,34 @@ func UnaryClientInterceptor() grpc.UnaryClientInterceptor {
64
94
65
95
// StreamServerInterceptor returns a new streaming server interceptor that validates incoming messages.
66
96
//
97
+ // If `all` is false, the interceptor returns first validation error. Otherwise the interceptor
98
+ // returns ALL validation error as a wrapped multi-error.
99
+ // Note that generated codes prior to protoc-gen-validate v0.6.0 do not provide an all-validation
100
+ // interface. In this case the interceptor fallbacks to legacy validation and `all` is ignored.
67
101
// The stage at which invalid messages will be rejected with `InvalidArgument` varies based on the
68
102
// type of the RPC. For `ServerStream` (1:m) requests, it will happen before reaching any userspace
69
103
// handlers. For `ClientStream` (n:1) or `BidiStream` (n:m) RPCs, the messages will be rejected on
70
104
// calls to `stream.Recv()`.
71
- func StreamServerInterceptor () grpc.StreamServerInterceptor {
105
+ func StreamServerInterceptor (all bool ) grpc.StreamServerInterceptor {
72
106
return func (srv interface {}, stream grpc.ServerStream , info * grpc.StreamServerInfo , handler grpc.StreamHandler ) error {
73
- wrapper := & recvWrapper {stream }
107
+ wrapper := & recvWrapper {
108
+ all : all ,
109
+ ServerStream : stream ,
110
+ }
74
111
return handler (srv , wrapper )
75
112
}
76
113
}
77
114
78
115
type recvWrapper struct {
116
+ all bool
79
117
grpc.ServerStream
80
118
}
81
119
82
120
func (s * recvWrapper ) RecvMsg (m interface {}) error {
83
121
if err := s .ServerStream .RecvMsg (m ); err != nil {
84
122
return err
85
123
}
86
- if err := validate (m ); err != nil {
124
+ if err := validate (m , s . all ); err != nil {
87
125
return err
88
126
}
89
127
return nil
0 commit comments