Contents
Overview
The Helidon JSON-RPC client API is part of the WebClient API, and can be used to create JSON-RPC 2.0 client applications. It offers built-in support to invoke JSON-RPC server methods with minimal effort, including handling of JSON parameters and processing of JSON responses.
Maven Coordinates
To enable WebClient/JSON-RPC, add the following dependency to your project’s pom.xml (see Managing Dependencies).
<dependency>
<groupId>io.helidon.webclient</groupId>
<artifactId>helidon-webclient-jsonrpc</artifactId>
</dependency>Usage
Simple Requests
An instance of JsonRpcClient can be obtained from a configured WebClient instance as shown next:
WebClient webClient = WebClient.builder()
.baseUri("http://localhost:8080/rpc")
.build();
JsonRpcClient client = webClient.client(JsonRpcClient.PROTOCOL);The WebClient instance is configured with a base URI and the JsonRpcClient instance is created from it passing the JsonRpcClient.PROTOCOL selector.
To create a request, simply pass the method name, the ID and some parameters using the fluent API provided. Parameters must be JSON values, but simple Java types such as String and int are supported and mapped to the corresponding JSON types automatically.
JsonRpcClientResponse res = client.rpcMethod("start")
.rpcId(1)
.param("when", "NOW")
.param("duration", "PT0S")
.path("/machine")
.submit();A JsonRpcClientResponse is a subtype of HttpClientResponse, so any methods available in the latter apply to the former. Thus, we can easily verify the HTTP status and then inspect if any JSON-RPC result has been returned as follows:
if (res.status() == Status.OK_200 && res.result().isPresent()) {
StartStopResult result = res.result().get().as(StartStopResult.class);
if (result.status().equals("RUNNING")) {
// success start!
}
}The HTTP status code is independent of any other error code in a JSON-RPC error response.
Every JSON-RPC response contains either a result or an error, and that is the reason why res.result() returns an optional value. The last step shows how the result is mapped to a StartStopResult instance using JSON-B. See JSON-RPC Server for more information on these types.
Batch Requests
The JSON-RPC client API also supports batching, whereby multiple method invocations can be aggregated and sent as a single unit for processing. The response to a batch request includes an entry for each of the invocations in the request; invocations are executed in order and can independently succeed or fail.
Here is an example that constructs a batch request to start and then stop a machine:
JsonRpcClientBatchRequest batch = client.batch("/machine");
batch.rpcMethod("start")
.rpcId(1)
.param("when", "NOW")
.param("duration", "PT0S")
.addToBatch()
.rpcMethod("stop")
.rpcId(2)
.param("when", "NOW")
.addToBatch();
JsonRpcClientBatchResponse batchRes = batch.submit();The response of type JsonClientBatchResponse shall include an entry for each of the invocations in the request. In this example, we can test that the response returned HTTP status 200 and has a size of 2, and then verify the results by binding them to StartStopResult instances using JSON-B.
if (batchRes.status() == Status.OK_200 && batchRes.size() == 2) {
Optional<JsonRpcResult> result0 = batchRes.get(0).result();
if (result0.get().as(StartStopResult.class).status().equals("RUNNING")) {
// successful start!
}
Optional<JsonRpcResult> result1 = batchRes.get(1).result();
if (result0.get().as(StartStopResult.class).status().equals("STOPPED")) {
// successful stop!
}
}As explained above, optional values are returned when trying to get a result since every individual batch response may include a result or an error.
Configuration
At the time of writing, there is no configuration that is specific to the JSON-RPC client API other than what is already provided by the WebClient API itself. Note that the type JsonRpcClientConfig —that can be used to create a JsonRpcClient instance— extends HttpClientConfig, so HTTP configuration applies to JSON-RPC clients as well.
Examples
The code snippets in this document are part of the JSON-RPC example available here: