How to define a GRPC service method without request parameter? - grpc

Normally definde a GRPC method as follows which has a request parameter HelloRequest:
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
But how to define a method without request parameter as following SayHello method:
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello () returns (HelloReply) {}
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}

Google's Well-Known Types includes Empty
Given that you must have a message for requests and responses, I think it's a good idea to define them in your protos even if initially empty unless you're absolutely confident that they'll always be empty:
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {}
message HelloReply {
string message = 1;
}

Related

Is there any way to get resquest type and response type by service type?

assume I have a gRPC service and a rpc method, defined by protobuf:
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
and I want to implement an class, received a template type named RpcMethod, can I get the resquest type and the response type specificed by RpcMethod type ?
for example:
template<typename RpcMethod>
class RpcCallData {
public:
using RequestType = RpcMethod::RequestType;
using ResponseType = RpcMethod::ResponseType;
private:
RequestType request;
ResponseType response;
};
RpcCallData<Greeter> data;
and then, I can deduce the type of request and response which is HelloRequest and HelloReply, respectively。

Using different proto files for server and client in gRPC

I have one proto file for gRPC server
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string othermessage = 1;
string message = 2;
string othermessage2 = 3;
}
My client don't need the fields othermessage and othermessage2. I make other proto file for client
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 2;
}
It works, but is it correct?
I see the following advantages: the client receive only the necessary data, the client's proto-file is not overloaded. For example, in sql we get only the required fields.
Maybe it's more efficient? Are all fields transmitted over the network or only the requested one?
I used the article Analyzing gRPC messages using Wireshark to validate fields sent over the network. All fields are sent. Therefore, using truncated proto files does not increase efficiency.
As a result, we can use the truncated proto file on the client, if it contains non-breaking differences, by analogy with non-breaking changes. This does not increase performance and can only be used to reduce the proto file on the client side.

Creating a Graph Webhook Subscription, why am I getting this message? "Response must exactly match validationToken query parameter"

I am new to Graph. I'm attempting to subscribe to changes in /users. Here's my Headers and POST to Graph:
//HTTP POST
//Host: https://graph.microsoft.com/v1.0/subscriptions
//Content-Type:applicaton/json
//Authorization: {auth key}
{
"changeType":"updated"
,"clientState":"myClientState"
,"resource":"/users"
,"notificationUrl":"[ngrok URL tunneling back to my local debug api instance]"
,"expirationDateTime":"2020-05-23T04:30:28.2257768+00:00"
}
And this is the relevant code on my core web API that gets the response from Graph:
// POST api/values
public IHttpActionResult Post ([FromUri]string validationToken)
{
Debug.WriteLine("validationToken string is: " + validationToken);
if (!String.IsNullOrEmpty(validationToken))
{
Debug.WriteLine("Token received, sending back token: " + validationToken);
return Ok(validationToken);
}
else
{
//...
}
}
I've tested this by hitting it up via Postman and it sends back exactly whatever query parameter it receives, as expected. When I send the POST call to Graph, my Web API gets the response. It has one parameter:
key: validationToken
value: 'Validation: Testing client application reachability for subscription Request-Id: ea95e0a8-55c6-42db-b7e6-441920ae9c15'
So that's what I send back. I always get this error after:
{
"error": {
"code": "InvalidRequest",
"message": "Subscription validation request failed. Response must exactly match validationToken query parameter.",
"innerError": {
"request-id": "ea95e0a8-55c6-42db-b7e6-441920ae9c15",
"date": "2020-05-18T20:07:17"
}
}
}
I've tried different encodings and confirmed that my Auth token is valid, and all endpoints are reaching each other OK. Honestly that doesn't really look like what I expect a validation token to look like - is that even it? I see nothing else in the POST body and there's no other params. Here's the exact request URI with the query parameter included:
https://localhost:44391/api/values?validationToken=Validation%3a+Testing+client+application+reachability+for+subscription+Request-Id%3a+ea95e0a8-55c6-42db-b7e6-441920ae9c15
Ensure validation token is returned as plain/text content-type. EG:
public IHttpActionResult Post([FromUri] string validationToken) {
Debug.WriteLine("validationToken string is: " + validationToken);
if (!String.IsNullOrEmpty(validationToken)) {
Debug.WriteLine("Token received, sending back token: " + validationToken);
return this.ResponseMessage(new HttpResponseMessage(HttpStatusCode.OK) {
Content = new StringContent(validationToken)
});
}
else {
return this.InternalServerError();
}
}
Replace return Ok(validationToken); by return Content(validationToken);.
Ok expects the parameter to be an object and might wrap what is passed in with JSON or XML depending on the request and the pipeline configuration.
Content expects the parameter to be a string and returns it as is.
You can use the postman collection to validate your endpoint's validation implementation and look at the sample for more information.

Is it possible to print HTTP Response inside addBodyEndHandler()?

I am trying to add log entries during start and as soon as request is responded (using ctx.addBodyEndHandler).
In below function foo what should be aaa?
private void foo(io.vertx.reactivex.ext.web.RoutingContext ctx) {
long start = System.currentTimeMillis();
String uuid = ctx.get("RequestIdentifier");
String clientAddress = ctx.request().remoteAddress().host();
LOG.info("Request ID: {}. Client IP: {}. Application type: {}. HTTP Method: {}. Body {}. Processing route: {}", uuid, clientAddress, this.getClientDescription(ctx.request()), ctx.request().method(), this.getRequestBody(ctx), ctx.request().uri());
ctx.addBodyEndHandler(ign -> {
LOG.info("Request ID: {} completed in {} ms. Response {}. Response code {}.", uuid, System.currentTimeMillis() - start, aaa, ctx.response().getStatusCode());
});
// more logic
}
You can't get the response body from the RoutingContext. Some responses may be very large so Vert.x doesn't store them.
If you are confident it will not harm your production system, you can store the body payload as context data before sending it:
routingContext.put("responseBody", content);
routingContext.response.end(content);
Then retrieve it in the bodyEnd handler:
String aaa = routingContext.get("responseBody");

does grpc service must have exactly one input parameter and one return value

let's say i have a proto file like this. can I define service like this
rpc SayHello () returns (Response) {} //service has no input
rpc SayHello (Request1,Request2) returns (Response) {}//service has two inputs
//.proto file
syntax = "proto3";
service Greeter{
rpc SayHello (Request) returns (Response) {}
}
message Request{
string request = 1;
}
message Response{
string response = 1;
}
gRPC service methods have exactly one input message and exactly one output message. Typically, these messages are used as input and output to only one method. This is on purpose, as it allows easily adding new parameters later (to the messages) while maintaining backward compatibility.
If you don't want any input or output parameters, you can use the well-known proto google.protobuf.Empty. However, this is discouraged as it prevents you from adding parameters to the method in the future. Instead, you would be encouraged to follow the normal practice of having a message for the request, but simply with no contents:
service Greeter {
rpc SayHello (SayHelloRequest) returns (SayHelloResponse) {}
}
message SayHelloRequest {} // service has no input
Similarly, if you want two request parameters, just include both in the request message:
message SayHelloRequest { // service has two inputs
string request = 1;
string anotherRequestParam = 2;
}

Resources