Skip to content

Commit

Permalink
protovalidate: add option to ignore certain message types
Browse files Browse the repository at this point in the history
  • Loading branch information
igor-tsiglyar authored and Igor Tsiglyar committed Dec 20, 2023
1 parent f35f047 commit 0c403b2
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 5 deletions.
40 changes: 40 additions & 0 deletions interceptors/protovalidate/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) The go-grpc-middleware Authors.
// Licensed under the Apache License 2.0.

// Copyright 2017 David Ackroyd. All Rights Reserved.
// See LICENSE for licensing terms.

package protovalidate

import (
"golang.org/x/exp/slices"
"google.golang.org/protobuf/reflect/protoreflect"
)

type options struct {
ignoreMessages []protoreflect.MessageType
}

type Option func(*options)

func evaluateOpts(opts []Option) *options {
optCopy := &options{}
for _, o := range opts {
o(optCopy)
}
return optCopy
}

// WithIgnoreMessages sets the messages that should be ignored as they are not yet ready
// for validation at the stage this middleware operates
func WithIgnoreMessages(msgs ...protoreflect.MessageType) Option {
return func(o *options) {
o.ignoreMessages = msgs
}
}

func (o *options) shouldIgnoreMessage(m protoreflect.MessageType) bool {
return slices.ContainsFunc(o.ignoreMessages, func(t protoreflect.MessageType) bool {
return m == t
})
}
13 changes: 8 additions & 5 deletions interceptors/protovalidate/protovalidate.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
)

// Option interface is currently empty and serves as a placeholder for potential future implementations.
// It allows adding new options without breaking existing code.
type Option interface {
unimplemented()
}
var (
ignoreMessages []protoreflect.MessageType

Check failure on line 19 in interceptors/protovalidate/protovalidate.go

View workflow job for this annotation

GitHub Actions / Linters (Static Analysis) for Go

var `ignoreMessages` is unused (unused)
)

// UnaryServerInterceptor returns a new unary server interceptor that validates incoming messages.
func UnaryServerInterceptor(validator *protovalidate.Validator, opts ...Option) grpc.UnaryServerInterceptor {
Expand All @@ -28,8 +27,12 @@ func UnaryServerInterceptor(validator *protovalidate.Validator, opts ...Option)
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (resp interface{}, err error) {
o := evaluateOpts(opts)
switch msg := req.(type) {
case proto.Message:
if o.shouldIgnoreMessage(msg.ProtoReflect().Type()) {
break
}
if err = validator.Validate(msg); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
Expand Down
14 changes: 14 additions & 0 deletions interceptors/protovalidate/protovalidate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@ func TestUnaryServerInterceptor(t *testing.T) {
assert.Error(t, err)
assert.Equal(t, codes.InvalidArgument, status.Code(err))
})

interceptor = protovalidate_middleware.UnaryServerInterceptor(validator,
protovalidate_middleware.WithIgnoreMessages(testvalidate.BadUnaryRequest.ProtoReflect().Type()),
)

t.Run("invalid_email_ignored", func(t *testing.T) {
info := &grpc.UnaryServerInfo{
FullMethod: "FakeMethod",
}

resp, err := interceptor(context.TODO(), testvalidate.BadUnaryRequest, info, handler)
assert.Nil(t, err)
assert.Equal(t, resp, "good")
})
}

type server struct {
Expand Down

0 comments on commit 0c403b2

Please sign in to comment.