Skip to content

Commit

Permalink
gRPC: simplify adding headers to client calls
Browse files Browse the repository at this point in the history
  • Loading branch information
michalszynkiewicz committed Aug 25, 2021
1 parent 9fc6d6d commit f555667
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 6 deletions.
38 changes: 38 additions & 0 deletions docs/src/main/asciidoc/grpc-service-consumption.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,44 @@ quarkus.grpc.clients.hello.deadline=2s <1>
----
<1> Set the deadline for all injected clients.

== gRPC Headers
Similarly to HTTP, alongside the message, gRPC calls can carry headers.
Headers can be useful e.g. for authentication.

To set headers for a gRPC call, create a client with headers attached and then perform the call on this client:
[source,java]
----
import javax.enterprise.context.ApplicationScoped;
import examples.Greeter;
import examples.HelloReply;
import examples.HelloRequest;
import io.grpc.Metadata;
import io.quarkus.grpc.GrpcClient;
import io.quarkus.grpc.GrpcClientUtils;
import io.smallrye.mutiny.Uni;
@ApplicationScoped
public class MyService {
@GrpcClient
Greeter client;
public Uni<HelloReply> doTheCall() {
Metadata extraHeaders = new Metadata();
if (headers) {
extraHeaders.put("my-header", "my-interface-value");
}
Greeter alteredClient = GrpcClientUtils.attachHeaders(client, extraHeaders); // <1>
return alteredClient.sayHello(HelloRequest.newBuilder().setName(name).build()); // <2>
}
}
----
<1> Alter the client to make calls with the `extraHeaders` attached
<2> Perform the call with the altered client. The original client remains unmodified

`GrpcClientUtils` work with all flavors of clients.

== Client Interceptors

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ public class {{serviceName}}Client implements {{serviceName}}, MutinyClient<{{cl
this.stub = stubConfigurator.apply(name,{{classPrefix}}{{serviceName}}Grpc.new{{classPrefix}}Stub(channel));
}

private {{serviceName}}Client({{classPrefix}}{{serviceName}}Grpc.{{classPrefix}}{{serviceName}}Stub stub) {
this.stub = stub;
}

public {{serviceName}}Client cloneWith({{classPrefix}}{{serviceName}}Grpc.{{classPrefix}}{{serviceName}}Stub stub) {
return new {{serviceName}}Client(stub);
}

@Override
public {{classPrefix}}{{serviceName}}Grpc.{{classPrefix}}{{serviceName}}Stub getStub() {
return stub;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.quarkus.grpc;

import io.grpc.Metadata;
import io.grpc.stub.AbstractStub;
import io.grpc.stub.MetadataUtils;
import io.quarkus.grpc.runtime.MutinyClient;

/**
* gRPC client utilities
*/
public class GrpcClientUtils {

/**
* Attach headers to a gRPC client.
*
* To make a call with headers, first invoke this method and then perform the intended call with the <b>returned</b> client
*
* @param client any kind of gRPC client
* @param extraHeaders headers to attach
* @param <T> type of the client
* @return a client with headers attached
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static <T> T attachHeaders(T client, Metadata extraHeaders) {
if (client == null) {
throw new NullPointerException("Cannot attach headers to a null client");
}
if (client instanceof AbstractStub) {
return (T) MetadataUtils.attachHeaders((AbstractStub) client, extraHeaders);
} else if (client instanceof MutinyClient) {
MutinyClient mutinyClient = (MutinyClient) client;
AbstractStub stub = MetadataUtils.attachHeaders(mutinyClient.getStub(), extraHeaders);
return (T) ((MutinyClient) client).cloneWith(stub);
} else {
throw new IllegalArgumentException("Unsupported client type " + client.getClass());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ public interface MutinyClient<T extends AbstractStub<T>> {
*/
T getStub();

MutinyClient<T> cloneWith(T stub);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,13 @@
import javax.ws.rs.core.MediaType;

import examples.Greeter;
import examples.GreeterClient;
import examples.GreeterGrpc;
import examples.HelloReply;
import examples.HelloRequest;
import examples.MutinyGreeterGrpc;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;
import io.quarkus.grpc.GrpcClient;
import io.quarkus.grpc.GrpcClientUtils;
import io.smallrye.mutiny.Uni;

@Path("/hello")
Expand All @@ -48,7 +47,7 @@ public String helloBlocking(@PathParam("name") String name, @QueryParam("headers
if (headers) {
extraHeaders.put(EXTRA_BLOCKING_HEADER, "my-blocking-value");
}
HelloReply reply = MetadataUtils.attachHeaders(blockingHelloClient, extraHeaders)
HelloReply reply = GrpcClientUtils.attachHeaders(blockingHelloClient, extraHeaders)
.sayHello(HelloRequest.newBuilder().setName(name).build());
return generateResponse(reply);

Expand All @@ -61,7 +60,7 @@ public Uni<String> helloMutiny(@PathParam("name") String name, @QueryParam("head
if (headers) {
extraHeaders.put(EXTRA_HEADER, "my-extra-value");
}
MutinyGreeterGrpc.MutinyGreeterStub alteredClient = MetadataUtils.attachHeaders(mutinyHelloClient, extraHeaders);
MutinyGreeterGrpc.MutinyGreeterStub alteredClient = GrpcClientUtils.attachHeaders(mutinyHelloClient, extraHeaders);
return alteredClient.sayHello(HelloRequest.newBuilder().setName(name).build())
.onItem().transform(this::generateResponse);
}
Expand All @@ -74,8 +73,7 @@ public Uni<String> helloInterface(@PathParam("name") String name, @QueryParam("h
extraHeaders.put(INTERFACE_HEADER, "my-interface-value");
}

MutinyGreeterGrpc.MutinyGreeterStub stub = ((GreeterClient) interfaceHelloClient).getStub();
MutinyGreeterGrpc.MutinyGreeterStub alteredClient = MetadataUtils.attachHeaders(stub, extraHeaders);
Greeter alteredClient = GrpcClientUtils.attachHeaders(interfaceHelloClient, extraHeaders);

return alteredClient.sayHello(HelloRequest.newBuilder().setName(name).build())
.onItem().transform(this::generateResponse);
Expand Down

0 comments on commit f555667

Please sign in to comment.