Consuming a gRPC Service
gRPC services can be injected in your application code.
Consuming gRPC services requires the gRPC classes to be generated. Place your proto files in src/main/proto and run mvn compile . |
Stubs and Injection
gRPC generation provides several stubs, providing different way to consume a service. Quarkus gRPC can inject:
blocking stubs
reactive stubs based on Mutiny
In addition, it also can inject the gRPC io.grpc.Channel
, that lets you create other types of stubs.
@Inject @GrpcService("hello-service")
MutinyGreeterGrpc.MutinyGreeterStub mutiny;
@Inject @GrpcService("hello-service")
GreeterGrpc.GreeterBlockingStub blocking;
@Inject @GrpcService("hello-service")
Channel channel;
The stub class names are computed from the service name. For example, if you use Greeter
as service name as in:
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
The Mutiny stub name is: MutinyGreeterGrpc.MutinyGreeterStub
The blocking stub name is: GreeterGrpc.GreeterBlockingStub
Client injection must be qualified using @GrpcService
. This annotation indicates the configuration prefix used to configure the service. For example, if you set it to hello-service
, configuring the host of the service is done using hello-service.host
.
Examples
Using a blocking and mutiny stubs
@Inject @GrpcService("hello") GreeterGrpc.GreeterBlockingStub blockingHelloService;
@Inject @GrpcService("hello") MutinyGreeterGrpc.MutinyGreeterStub mutinyHelloService;
@GET
@Path("/blocking/{name}")
public String helloBlocking(@PathParam("name") String name) {
return blockingHelloService.sayHello(HelloRequest.newBuilder().setName(name).build()).getMessage();
}
@GET
@Path("/mutiny/{name}")
public Uni<String> helloMutiny(@PathParam("name") String name) {
return mutinyHelloService.sayHello(HelloRequest.newBuilder().setName(name).build())
.onItem().transform(HelloReply::getMessage);
}
Note that in this example, the quarkus.grpc.clients.hello.host
property must be set.
Handling streams
gRPC allows sending and receiving streams:
service Streaming {
rpc Source(Empty) returns (stream Item) {} // Returns a stream
rpc Sink(stream Item) returns (Empty) {} // Reads a stream
rpc Pipe(stream Item) returns (stream Item) {} // Reads a streams and return a streams
}
Using the Mutiny stub, you can interact with these as follows:
package io.quarkus.grpc.example.streaming;
import io.grpc.examples.streaming.Empty;
import io.grpc.examples.streaming.Item;
import io.grpc.examples.streaming.MutinyStreamingGrpc;
import io.quarkus.grpc.runtime.annotations.GrpcService;
import io.smallrye.mutiny.Multi;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/streaming")
@Produces(MediaType.APPLICATION_JSON)
public class StreamingEndpoint {
@Inject @GrpcService("streaming") MutinyStreamingGrpc.MutinyStreamingStub client;
@GET
public Multi<String> invokeSource() {
// Retrieve a stream
return client.source(Empty.newBuilder().build())
.onItem().transform(Item::getValue);
}
@GET
@Path("sink/{max}")
public Uni<Void> invokeSink(@PathParam("max") int max) {
// Send a stream and wait for completion
Multi<Item> inputs = Multi.createFrom().range(0, max)
.map(i -> Integer.toString(i))
.map(i -> Item.newBuilder().setValue(i).build());
return client.sink(inputs).onItem().ignore().andContinueWithNull();
}
@GET
@Path("/{max}")
public Multi<String> invokePipe(@PathParam("max") int max) {
// Send a stream and retrieve a stream
Multi<Item> inputs = Multi.createFrom().range(0, max)
.map(i -> Integer.toString(i))
.map(i -> Item.newBuilder().setValue(i).build());
return client.pipe(inputs).onItem().transform(Item::getValue);
}
}
Client configuration
For each gRPC service you inject in your application, you can configure the following attributes:
About the Duration format The format for durations uses the standard You can also provide duration values starting with a number. In this case, if the value consists only of a number, the converter treats the value as seconds. Otherwise, |
The service-name
is the name set in the @GrpcService
.
Example of configuration
The 2 following examples uses hello as service name. Don’t forget to replace it with the name you used in in the @GrpcService
annotation.
Enabling TLS
To enable TLS, use the following configuration:
quarkus.grpc.clients.hello.host=localhost
quarkus.grpc.clients.hello.ssl.trust-store=src/main/resources/tls/ca.pem
When SSL/TLS is configured, plain-text is automatically disabled. |
TLS with Mutual Auth
To use TLS with mutual authentication, use the following configuration:
quarkus.grpc.clients.hello.host=localhost
quarkus.grpc.clients.hello.plain-text=false
quarkus.grpc.clients.hello.ssl.certificate=src/main/resources/tls/client.pem
quarkus.grpc.clients.hello.ssl.key=src/main/resources/tls/client.key
quarkus.grpc.clients.hello.ssl.trust-store=src/main/resources/tls/ca.pem