-
Notifications
You must be signed in to change notification settings - Fork 833
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gRPC request validation (server-side) #487
base: master
Are you sure you want to change the base?
Conversation
This looks like an interesting proposal. Such as |
Interesting in a good or bad way? 🙂 But I decided not to use javax validations, because the proto files generate the Java classes used for requests and there is no possibility to add validation annotation or other code to the generated classes. I mean you could validate them programmatically like I did with the ones right now, but it would have added an extra library in contrast to just simply implement the given The second one mentioned In general, what are your thoughts on this @ST-DDT? |
In a good way. I already thought about adding support for it, I just wasn't sure which direction grpc would go regarding validation: grpc/grpc-java#3926
Well, there is actually no need to add the annotations to the classes itself. You can also use protoc to generate companion classes, such as the validators generated by envoyproxy. These could also be used to generate a programmatic configuration. I'm actually quite torn which way is the best, but I would like to reuse existing APIs if possible to make this library/it's features more familiar for the users. Also if the validation configuration is embedded into the proto file, then there won't be confusion why the server rejected a certain value and other implementations can reuse the validation constraints. grpc/proto is centered around |
I know that you can generate them programmatically, my thought was keep it as lightweight as possible since it would only contain one interface. But of course if you decide to use the generated proto and it works in combination with the javax validation, it does make sense to use it.
I mean if you look at it this way, most user which are using grpc-spring-boot-starter will use given features by the framework to validate their request or implement their own stuff. I think not that many people will be forwarded from the proto validation library/framework to the grpc-spring-boot-starter. So i think this is kinda pathbreaking, since you can decide what to offer.
This is true, it offers some kind of documentation like a swagger file. For me this is kinda twisted, it offers the mentioned benefits, but you limit developer to use it and offer no alternative with explicit Java code. Would love to head some feedback about it. What do you think about offering both ways? |
Having both ways might be a good solution. Maybe outline all three variants.
But I would like to put the discussion down until 2.12 is released, because I'm really busy currently. |
Hi @ST-DDT, any new updates in this matter? |
I'm really busy this month, so I might not have the time to get to it soon. |
@anjeyy hello. I am a Korean developer. |
@sangyongchoi Hey there. Is there anything new regarding validations in terms of already mentioned libraries? @ST-DDT |
@anjeyy There is nothing new in terms of libraries. |
No, I'm fine with it. That's what OpenSource is for. |
@ST-DDT thank you 😄 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@anjeyy please confirm my comment
Metadata headers, | ||
ServerCallHandler<ReqT, RespT> next) { | ||
|
||
Listener<ReqT> delegate = next.startCall(call, headers); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if what i know is right, reason printing call already closed is next.startCall
is non thread-safe.
solution : https://groups.google.com/g/grpc-io/c/_osH2D6L9Ck
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what exactly happens, but it's probably not related to mutli-threading, but "owning" the server call instance.
You only close the call, but you never tell the control structure, that you have done so, thus the request processing "continues" as normal. Then the close you have send kicks in and the server tries to properly close the connection, thus sending the close twice. Which is probably the exception you are seeing.
Instead of (or maybe in addition to) closing the call instance, you have to throw a RuntimeStatusException
. This will cause the control structure to shutdown with you error status and thus avoids the duplicate close.
(I haven't tested this, just my guess from your one sentence without stacktrace)
I did something similar here:
https://github.com/yidongnan/grpc-spring-boot-starter/blob/master/grpc-server-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/server/security/interceptors/ExceptionTranslatingServerInterceptor.java#L44
Alternatively do it like this (This is also from a validation framework, so it might work better for your usecase):
https://github.com/envoyproxy/protoc-gen-validate/blob/5ef93ae28a92362ede78aaa49c5c3e290c70e324/java/pgv-java-grpc/src/main/java/io/envoyproxy/pgv/grpc/ValidatingServerInterceptor.java
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh.. thank you 😄
@ddcprg Please explain what you are asking for exactly.
|
I believe, there is no need to proceed with PR any further as protovalidate project should cover validation cases in a much abstract way. I'm talking about this one: https://github.com/bufbuild/protovalidate and specifically for JVM-based https://github.com/bufbuild/protovalidate-java |
protovalidate falls short when it comes to add more complex validations since is all declarative, for example it is impossible to validate with declarative rules that the value of one of the request parameters is defined in another system, e.g. a database or third-party service. I think having both options also let users use whatever is more convenient for their use case |
I came across some repeating pattern, a request validation. Clients send a gRPC request and with this functionality just implement
GrpcConstraintValidator
with validation-logic and annotate with@GrpcConstraint
and the validation is being processed.By the time the request enters implemented service via
@GrpcService
, the request was validated successful. Removes boilerplate-code and preserves the real business-logic inside@GrpcService
.Following a simple use case:
Proto-file - Consider your proto-file, here just a simple one to illustrate use-case
Now all you need to do, create Validator classes
DocumentRequestValidator
There can also be multiple Validator of the same Request-Message
Side-Note: If an uncatched exception is thrown inside a Validator the return type to the client is
Status.INTERNAL..
, otherwise it'sStatus.INVALID_ARGUMENT..
for failed validations.Currently the implementation works well - the response to the client is exactly how it is inteded to be.
However, i came across a (cosmetic?) problem and i do not now how to resolve it elegantly, may be you guys have some suggestions. Situation: The validation fails (either with returning false from
GrpcConstraintValidator.isValid(....)
or a exception is trown inside the validation), in both cases theserverCall.close(...)
is called and the console prints following thingMy guess is there is not much we can do, since this message is from
io.grpc.internal
, but if you have any ideas, please let me know. Like i said for me this is more of a cosmetic error, sinde it can be printed more than once if the close is delegated or being called multiple times.I'm interesseted in your feedback or in any way what improvements can be made. If you have questions, just let me know.
TODO