Skip to content

Commit

Permalink
Documents gRPC MP Client API.
Browse files Browse the repository at this point in the history
Signed-off-by: Santiago Pericas-Geertsen <[email protected]>
  • Loading branch information
spericas committed Aug 15, 2024
1 parent 8856af8 commit 200fe52
Show file tree
Hide file tree
Showing 2 changed files with 228 additions and 0 deletions.
227 changes: 227 additions & 0 deletions docs/src/main/asciidoc/mp/grpc/client.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
///////////////////////////////////////////////////////////////////////////////

Copyright (c) 2019, 2024 Oracle and/or its affiliates.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

///////////////////////////////////////////////////////////////////////////////
= gRPC MicroProfile Client
:description: Building Helidon gRPC MicroProfile Clients
:keywords: helidon, java, grpc, microprofile, micro-profile, mp
:feature-name: gRPC MicroProfile Clients
:rootdir: {docdir}/../..
:microprofile-bundle: false
include::{rootdir}/includes/mp.adoc[]
== Contents
- <<Overview, Overview>>
- <<Maven Coordinates, Maven Coordinates>>
- <<API, API>>
- <<Configuration, Configuration>>
** <<Configuring TLS, Configuring TLS>>
- <<Usage, Usage>>
** <<Using Channels, Using Channels>>
** <<Using the Client Interface in an Application, Using the Client Interface in an Application>>
** <<Building a gRPC Client, Building a gRPC Client>>
- <<Examples, Examples>>
== Overview
Building Java-based gRPC clients using the Helidon MP gRPC APIs is very simple and removes a lot of
the boilerplate code typically associated to more traditional approaches of writing gRPC Java clients.
At its simplest, a gRPC Java client can be written using nothing more than a suitably annotated interface.
include::{rootdir}/includes/dependencies.adoc[]
[source,xml]
----
<dependency>
<groupId>io.helidon.microprofile.grpc</groupId>
<artifactId>helidon-microprofile-grpc-client</artifactId>
</dependency>
----
== API
The following annotations are used to work with Helidon MP gRPC clients:
* `@Grpc.GrpcChannel` - an annotation used to inject a gRPC channel.
* `@Grpc.GrpcProxy` - an annotation used to mark an injection point for a gRPC service client proxy.
* `@Grpc.GrpcService` - an annotation used to mark a class as representing a gRPC service.
== Configuration
For a gRPC client to connect to a server, it requires a Channel. Channels are configured in the `grpc` section
of the Helidon application configuration. The examples below use an `application.yaml` file but there are many other
ways to use and override xref:{rootdir}/mp/config/introduction.adoc[configuration in Helidon].
.General Form of a gRPC Channels Configuration
[source,yaml]
----
grpc:
client:
channels: # <1>
- name: "string-channel" # <2>
host: localhost # <3>
port: 8080 # <4>
----
<1> Channels are configured in the `channels` section.
<2> The name of the channel as referred to in the application code.
<3> The host name for the channel (defaults to localhost).
<4> The port number for the channel (defaults to 1408).
While most client applications only connect to a single server, it is possible to configure multiple
named channels if the client needs to connect to multiple servers.
=== Configuring TLS
gRPC runs on top of HTTP/2 which prefers secure TLS connections. Most gRPC channels will also
include a section to configure TLS. Here is a sample of that configuration for the "string-channel":
[source,yaml]
----
grpc:
client:
channels:
- name: "string-channel"
port: 0
tls:
trust:
keystore:
passphrase: "password"
trust-store: true
resource:
resource-path: "client.p12"
private-key:
keystore:
passphrase: "password"
resource:
resource-path: "client.p12"
----
TLS in the gRPC Microprofile Client is configured in the same was as in other Helidon
components such as the webserver. For more information see
xref:{rootdir}/se/webserver.adoc#_configuring_tls[Configuring TLS].
== Usage
=== The Client Service Interface
The next step is to produce an interface with the service methods that the client requires.
For example, suppose we have a simple server side service that has a unary method to convert
a string to uppercase. To write a client for this service, all that is required is an interface.
[source,java]
----
@ApplicationScoped
@Grpc.GrpcService("StringService")
@Grpc.GrpcChannel("string-channel")
interface StringServiceClient {
@Grpc.Unary
String upper(String s);
}
----
There is no need to write any code to implement the client. The Helidon MP gRPC APIs will
create a dynamic proxy for the interface using the information from the annotations and
method signatures.
The interface in the example above used the same method signature as the server but this
does not have to be the case. It could have used any supported signature for a unary method.
For example, it could just have easily been written using the standard unary method signature:
[source,java]
----
@ApplicationScoped
@Grpc.GrpcService("StringService")
@Grpc.GrpcChannel("string-channel")
interface StringServiceClient {
@Grpc.Unary
void upper(String s, StreamObserver<String> response);
}
----
=== Using Channels
Once one or more channels have been configured, then they can be used by the client code.
The simplest way to use a channel is to inject it into beans using CDI. The Helidon gRPC
client APIs have CDI producers that can provide `io.grpc.Channel` instances.
For example, a class might have an injectable `io.grpc.Channel` field:
[source,java]
----
@Inject // <1>
@Grpc.GrpcChannel("string-channel") // <2>
private Channel channel;
----
<1> The `@Inject` annotation tells CDI to inject the channel.
<2> The `@Grpc.GrpcChannel` annotation is the qualifier that supplies the channel name.
This is the same name as used in the channel configuration in the examples provided in
the <<Configuration, configuration section>>.
When an instance of the CDI bean with the channel field is instantiated, a channel will
be injected into it.
=== Using the Client Interface in an Application
Now that there is a client interface and a channel configuration, we can then use these
in the client application.
We can declare a field of the same type as the client service interface in the application
class that requires the client. The field is then annotated so that CDI will inject the
client proxy into the field.
[source,java]
----
@ApplicationScoped
public class Client {
@Inject // <1>
@Grpc.GrpcProxy // <2>
@Grpc.GrpcChannel("string-channel") // <3>
private StringServiceClient stringServiceClient;
}
----
<1> The `@Inject` annotation tells the CDI to inject the client implementation.
<2> The `@GrpcProxy` annotation is used by the CDI container to match the injection point to the gRPC MP APIs provider.
<3> The `@GrpcChannel` annotation identifies the gRPC channel to be used by the client. The name used in the annotation refers to
a channel name in the application configuration.
When the CDI container instantiates instances of the `Client`, it will inject a dynamic proxy into the `stringService` field
and then any code in methods in the `Client` class can call methods on the `StringService` which will be translated to gRPC calls.
In the example above, there is no need to use a `Channel` directly. The correct channel is added to the dynamic client
proxy internally by the Helidon MP gRPC APIs.
=== Building a gRPC Client
There are a few steps to building and using a gRPC client in Helidon MP.
As discussed in the xref:server.adoc#_defining_service_methods[Defining Service methods] section of the xref:server.adoc[Server-Side Services], there are four different types of gRPC method.
* `Unary` - a simple method with at most a single request value and returning at most a single response value.
* `Server Streaming` - a method that takes at most a single request value but may return zero or more response values.
* `Client Streaming` - a request that takes one or more request values and returns at most one response value.
* `Bi-directional Streaming` - a method that can take one or more request values and return zero or more response values.
And as with the server-side APIs, the Helidon MP gRPC client APIs support a number of different methodsignatures for each of the
different gRPC method types.
== Examples
link:{helidon-github-tree-url}/examples/grpc/microprofile/basic-client[Basic gRPC Client] example demonstrates a
simple gRPC client that invokes services from deployed gRPC server applications provided in the
link:{helidon-github-tree-url}/examples/grpc/microprofile/basic-server-implicit[Basic gRPC Server] and
link:{helidon-github-tree-url}/examples/grpc/microprofile/metrics[gRPC Server metrics] examples.
1 change: 1 addition & 0 deletions docs/src/main/asciidoc/sitegen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ backend:
value: "swap_horiz"
sources:
- "server.adoc"
- "client.adoc"
- type: "PAGE"
title: "Health Checks"
source: "health.adoc"
Expand Down

0 comments on commit 200fe52

Please sign in to comment.