////
This guide is maintained in the main Quarkus repository
and pull requests should be submitted there:
https://github.com/quarkusio/quarkus/tree/master/docs/src/main/asciidoc
////
= Consuming a gRPC Service

include::./attributes.adoc[]

gRPC services can be injected in your application code.

IMPORTANT: 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.

[source, java]
----
@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:

[source]
----
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

[source, java]
----
@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:

[source]
----
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:

[source, java]
----
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:

include::{generated-dir}/config/quarkus-grpc-config-group-config-grpc-client-configuration.adoc[opts=optional, leveloffset=+1]

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.
Note that all paths in the configuration may either specify a resource on the classpath
(typically from `src/main/resources` or its subfolder) or an external file.

[source,properties]
----
quarkus.grpc.clients.hello.host=localhost

# either a path to a classpath resource or to a file:
quarkus.grpc.clients.hello.ssl.trust-store=tls/ca.pem
----

NOTE: When SSL/TLS is configured, `plain-text` is automatically disabled.

=== TLS with Mutual Auth

To use TLS with mutual authentication, use the following configuration:

[source,properties]
----
quarkus.grpc.clients.hello.host=localhost
quarkus.grpc.clients.hello.plain-text=false

# all the following may use either a path to a classpath resource or to a file:
quarkus.grpc.clients.hello.ssl.certificate=tls/client.pem
quarkus.grpc.clients.hello.ssl.key=tls/client.key
quarkus.grpc.clients.hello.ssl.trust-store=tls/ca.pem
----

== Client Interceptors

You can implement a gRPC client interceptor by implementing an `@ApplicationScoped` bean implementing `io.grpc.ClientInterceptor`:

[source, java]
----
@ApplicationScoped
public class MyInterceptor implements ClientInterceptor {

    @Override
    public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method,
            CallOptions callOptions, Channel next) {
       // ...
    }
}
----

TIP: Check the https://grpc.github.io/grpc-java/javadoc/io/grpc/ClientInterceptor.html[ClientInterceptor JavaDoc] to properly implement your interceptor.

When you have multiple client interceptors, you can order them by implementing the `javax.enterprise.inject.spi.Prioritized` interface:

source, java]
----
@ApplicationScoped
public class MyInterceptor implements ClientInterceptor, Prioritized {

    @Override
    public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method,
            CallOptions callOptions, Channel next) {
       // ...
    }

    @Override
    public int getPriority() {
        return 10;
    }
}
----

Interceptors with the highest priority are called first.
The default priority, used if the interceptor does not implement the `Prioritized` interface, is `0`.

