Helidon SE WebClient Guide

This guide describes how to create a sample Helidon SE project that can be used to run some basic examples using WebClient.

What you need

For this 15 minute tutorial, you will need the following:

Prerequisite product versions for Helidon 4.4.1
Java SE 21 (Open JDK 21)Helidon requires Java 21+ (25+ recommended).
Maven 3.8+Helidon requires Maven 3.8+.
Docker 18.09+If you want to build and run Docker containers.
Kubectl 1.16.5+If you want to deploy to Kubernetes, you need kubectl and a Kubernetes cluster (you can install one on your desktop).
Verify Prerequisites
java -version
mvn --version
docker --version
kubectl version
Copied
Setting JAVA_HOME
# On Mac
export JAVA_HOME=`/usr/libexec/java_home -v 21`

# On Linux
# Use the appropriate path to your JDK
export JAVA_HOME=/usr/lib/jvm/jdk-21
Copied

WebClient Features

Helidon’s WebClient is used to perform HTTP REST requests to target endpoints and handle their responses.

WebClient provides the following features:

  • User-friendly: Every client and request is created by a builder pattern, so it improves readability and code maintenance.

  • Following redirects: The WebClient is able to follow the redirect chain and perform requests on the correct endpoint for you. You no longer have to point your client to the correct/final endpoint.

  • Tracing, metrics and security propagation: When you configure the Helidon WebServer to use tracing, metrics and security, the settings are automatically propagated to the WebClient and used during request/response.

For more information about the WebClient, please refer to the WebClient Introduction.

WebClient Usage

Create a sample SE project

Generate the project sources using the Helidon SE Maven archetype. The result is a simple project that can be used for the examples in this guide.

Run the Maven archetype:
mvn -U archetype:generate -DinteractiveMode=false \
    -DarchetypeGroupId=io.helidon.archetypes \
    -DarchetypeArtifactId=helidon-quickstart-se \
    -DarchetypeVersion=4.4.1 \
    -DgroupId=io.helidon.examples \
    -DartifactId=helidon-quickstart-se \
    -Dpackage=io.helidon.examples.quickstart.se
Copied

You should now have a directory called helidon-quickstart-se.

Open this directory
cd helidon-quickstart-se
Copied

The Helidon quickstart is a greeting application supporting several HTTP requests such as GET and PUT. Using it will be time-saving for this exercise as it will allow us to modify the project to demonstrate some of the Webclient features and usability, rather than start from scratch.

The quickstart example utilizes WebClient solely for testing purposes, with the dependency configured under the test scope. To use WebClient within your application, remove the test scope from the dependency in the pom.xml.

Remove the test scope from WebClient dependency
<dependency>
    <groupId>io.helidon.webclient</groupId>
    <artifactId>helidon-webclient</artifactId>
</dependency>
Copied

Add ClientExample class

In io.helidon.examples.quickstart.se package, create a new class named ClientExample. This class will use the WebClient to send request to the greeting application.

Create ClientExample class:
public class ClientExample {

    public static void main(String[] args) {

    }
}
Copied

Add the following code to the main method to create a WebClient instance. The builder approach allows you to create the WebClient with specific settings and improves the readability and simplicity of the code.

Add WebClient instance to the main method:
WebClient webClient = WebClient.builder()
        .baseUri("http://localhost:8080") 
        .build();
Copied
  • The base URI of the outbound requests.

By default, the Helidon quickstart application runs on localhost:8080. If for some reason the host name or port number of the quickstart application is changed, make sure that the baseURI is also modified to reflect that change. Once built, the WebClient can be used to send a GET request to the greeting application.

Send a GET request to the target endpoint:
ClientResponseTyped<String> response = webClient.get() 
        .path("/greet") 
        .request(String.class); 
String entityString = response.entity(); 
System.out.println(entityString);
Copied
  • Create an HTTP GET request.
  • Target endpoint path.
  • Execute the request
  • Return response entity handled as a String.

The path method appends /greet to the WebClient base URI which results to the request URI becoming http://localhost:8080/greet. The received response entity will be a greeting message and will be automatically handled as a String. If no specific type is set in the method request(), HttpClientResponse will be returned by default. This HttpClientResponse object contains response code, headers and entity.

Run the application

Build the quickstart:
mvn package
Copied

This command will create helidon-quickstart-se.jar in the target folder.

Run the greeting application:
java -cp target/helidon-quickstart-se.jar io.helidon.examples.quickstart.se.Main
Copied

Open a new command prompt or terminal and run the ClientExample class you just created.

Run the client application:
java -cp target/helidon-quickstart-se.jar io.helidon.examples.quickstart.se.ClientExample
Copied
JSON response:
{"message":"Hello World!"}
Copied

When the ClientExample finishes its execution, you can stop the Main class by pressing CTRL+C.

Discover other WebClient functionality

In practice, String is not the most useful return type, since it usually needs some more handling. In this case, it could be more interesting to return an object of another type like a JSON object. One way to process a JSON object is by enabling Helidon’s built-in JSON-P support and this can be simply achieved by adding its dependency in the project’s pom.xml:

<dependency>
    <groupId>io.helidon.http.media</groupId>
    <artifactId>helidon-http-media-jsonp</artifactId>
</dependency>
Copied

Once the dependency is added, the feature will be automatically loaded as a service allowing the response methods to easily parse the JSON object.

Replace String with JsonObject:
ClientResponseTyped<JsonObject> response = webClient.get()
        .path("/greet/David")
        .request(JsonObject.class); 
String value = response.entity().getString("message"); 
System.out.println(value);
Copied
  • Request a JsonObject as return value.
  • Extract the value of the JsonObject with name of message.

In the URI, the String value following greet is a path parameter which allows the application to greet someone.

Output:
Hello David!
Copied

It is also possible to change the greeting word by using a PUT request to /greet/greeting path. The request also needs to include a body with JSON type and using a structure like {"greeting" : "value"}.

Modify the application greeting:
JsonObject entity = Json.createObjectBuilder() 
        .add("greeting", "Bonjour")
        .build();
webClient.put() 
        .path("/greet/greeting")
        .submit(entity); 
ClientResponseTyped<JsonObject> response = webClient.get() 
        .path("/greet/David")
        .request(JsonObject.class);
String entityString = response.entity().getString("message"); 
System.out.println(entityString);
Copied
  • Create a JsonObject with key greeting and value bonjour.
  • Create a PUT request.
  • Submit the JsonObject created earlier.
  • Execute a GET call to verify that the greeting has been changed.
  • Retrieve the greeting message from the JSON object

Executing the above code will yield this output showing that the greeting word has been changed.

Output:
Bonjour David!
Copied

WebClient Metrics

WebClient, like other Helidon components, supports Metrics. The following example introduces a counter metric that can be used to measure WebClient request activity. There are two ways to set up metrics, programmatically on the WebClient instance or manually using the configuration file.

Add metrics dependency

To enable support for this feature, the helidon-webclient-metrics dependency needs to be added .

Add the following dependency to pom.xml:
<dependency>
    <groupId>io.helidon.webclient</groupId>
    <artifactId>helidon-webclient-metrics</artifactId>
</dependency>
Copied

Set up metrics on WebClient instance

Metrics can be registered on the WebClient directly. The following example shows how a Counter metric can be defined, created and monitored.

Example of metric creation:
MeterRegistry METER_REGISTRY = Metrics.globalRegistry();

String metricName = "counter.GET.localhost"; 

Counter counter = METER_REGISTRY.getOrCreate(Counter.builder(metricName)); 
System.out.println(metricName + ": " + counter.count());

WebClientService clientServiceMetric = WebClientMetrics.counter()
        .methods(Method.GET)                // OPTIONAL
        .success(true)                      // OPTIONAL
        .errors(true)                       // OPTIONAL
        .description("Metric Description")  // OPTIONAL
        .nameFormat("counter.%1$s.%2$s") 
        .build(); 
Copied
  • Specify the metric name.
  • From the MeterRegistry, create a Counter metric using the specified metric name.
  • Specify how the name of the metric will be generated using the nameFormat.
  • Build a WebClient Metric Service that can count number of GET requests made.

In this example, the metric uses a Counter to measure the number of GET requests executed on the localhost. The format strings in the parameter value of nameFormat method will identify how the name of a metric will get generated:

  • %1$s = Request method

  • %2$s = Request host

  • %3$s = Response status

So for example, if the nameFormat value is metric.%1$s.%2$s.%3$s and a request uses a GET method, targeting a URL with localhost as the hostname, and got a response code of 200, that the final metric will get created with a name of metric.GET.localhost.200.

To register the metric service, simply use the addService method and pass in the created WebClient Metric Service as a parameter.

Add the metric service to the WebClient:
WebClient webClient = WebClient.builder()
        .baseUri("http://localhost:8080")
        .addService(clientServiceMetric) 
        .build();

webClient.get().path("/greet").request(); 
Copied
  • Register the metric service to the webclient.
  • Send an HTTP GET request

To verify that the metric is set up correctly, print the value of the Counter at the end of the main method.

Print the metric count
System.out.println(metricName + ": " + counter.count());
Copied

This will result to an output showing that a metric with the name of counter.GET.localhost was created with a count value of 1 indicating that it correctly measured the request that was just made.

Output:
counter.GET.localhost: 1
Copied

Set up metrics with configuration files

Using the configuration file can reduce the code complexity and make the metrics simpler to use. With this approach, it eliminates the need to modify the source code for scenarios where the metric settings have to be changed. The application.yaml file is the default configuration file for Helidon and can be used to set up metrics settings.

Example of metric configuration:
client:
  services:
    metrics:
      - type: COUNTER
        methods: ["GET"]
        description: "Metric Description"
        name-format: "counter.%1$s.%2$s"
Copied

In the example configuration definition above, the metrics configuration are located under client.services.metrics. The metric setting can start either by its type or methods. The configuration file uses the same keywords as the programmatic way. For example, type defines the kind of metric and methods identifies the http methods that will be measured.

Add the metric service to the WebClient via the Configuration:
MeterRegistry METER_REGISTRY = Metrics.globalRegistry();

String counterName = "counter.GET.localhost"; 

Counter counter = METER_REGISTRY.getOrCreate(Counter.builder(counterName)); 
System.out.println(counterName + ": " + counter.count());

Config config = Config.create(); 

WebClient webClient = WebClient.builder()
        .baseUri("http://localhost:8080")
        .config(config.get("client")) 
        .build();
webClient.get().path("/greet").request(); 
System.out.println(counterName + ": " + counter.count()); 
Copied
  • Choose the metric name.
  • Create counter metric from MeterRegistry.
  • Create a Helidon Config instance from default config file application.yaml.
  • Configure the WebClient using the client section from application.yaml.
  • Send an HTTP GET request
  • Print out the metric result

As demonstrated, using the configuration file reduces the amount of code needed in the source code. For more information about metrics, see the Helidon Metrics Guide.