HTTP Client
Fusion HTTP Client is based on java.net.http.HttpClient
. It is configured with ExtendedHttpClientConfiguration
which enables to:
- optionally provide a configured HttpClient
instance - otherwise the default JVM one is used, - optionally provide a set of RequestListener
s which listen for requests.
Request Listeners
Request listener is a callback triggered before and after each request. It enables to store data before the requests in the caller context and execute some callback once the request is finished. To pass data between both steps (since the request can be asynchronous or not) it uses a State
which can hold any data the listener needs.
TIP
|
if you write custom listeners (to add OpenTracing capabilities for example), you can make them implement |
Default Listeners
DefaultTimeout
This listener is pretty straight forward, if the request does not have a timeout, it sets it to the default one configured in the listener. It enables to enforce a global timeout to all requests.
SetUserAgent
This listener enforce a custom user-agent value. It defaults to chrome one.
ExchangeLogger
This listener enables to force all exchanges to be logged.
FilteringListener
This listener wraps another listener to filter the calls to before
/after
callbacks either based on the request or on the response. Can be useful to ignore some data (for example to only capture errors in HARDumperListener
).
TIP
|
for |
HARDumperListener
This listener enables to capture a HAR
dump of all exchanges which went through the client. It can be very useful to generate some test data you replay with a HAR server in a test or a demo environment.
It comes with its companion HARHttpClient
which enables to replay a HAR without actually doing the requests.
TIP
|
a sibling listener called |
IMPORTANT
|
the |
Sample usage
final var conf = new ExtendedHttpClientConfiguration();
// (optional) force a custom SSL context
conf.setDelegate(
HttpClient.newBuilder()
.sslContext(getSSLContext())
.build());
// (optional) force custom listeners
conf.setListeners(List.of(
new AutoTimeoutSetter(Duration.ofSeconds(3600)),
new AutoUserAgentSetter(),
new ExchangeLogger(
Logger.getLogger(getClass().getName()),
Clock.systemUTC(),
false)));
(Open) Tracing
IMPORTANT
|
this is not in the same module, you must add |
tracing
module provides a Tomcat valve you can set up on your web container to add tracing capabilities to your Tomcat:
final var listener = new TracingListener(
new ClientTracingConfiguration(), (1)
accumulator, (2)
new IdGenerator(IdGenerator.Type.HEX), (3)
new ServletContextAttributeEvaluator(servletRequest), (4)
systemUTC()); (5)
(6)
final var configuration = new ExtendedHttpClientConfiguration()
.setRequestListeners(List.of(listener));
final var client = new ExtendedHttpClient(configuration);
- The configuration enables to customize the span tags and headers to enrich the request with,
- The accumulator is what will send/log/... the spans once aggregated, ensure to configure it as needed,
-
The
IdGenerator
provides the span/trace identifiers, it must be compatible with your collector (hex
for zipkin for example), -
Actually a
Supplier<Span>
, the span evaluator enables to get parent span, here from therequest
in awebserver-tomcat
usingTracingvalve
but any evaluation will work, - The clock enables to timestamp the span and compute its duration,
- Finally, add the listener to your http client configuration and create your client.
IMPORTANT
|
the accumulator should generally be closed if you reuse |
Kubernetes client
kubernetes-client
modules providers a HTTP Client already configured for Kubernetes in cluster connection (from a POD). This will typically be used from an operator or cloud native application to call Kubernetes API using a plain and very light HTTP Client from the JVM.
TIP
|
indeed you can combine it with the enhanced HTTP Client configuring it in the |
Usage:
final var conf = new KubernetesClientConfiguration()
.setClientWrapper(client -> new ExtendedHttpClient(new ExtendedHttpClientConfiguration()
.setDelegate(client)));
final var k8s = new KubernetesClient(conf);
// now call any API you need:
final var response = k8s.send(
HttpRequest.newBuilder()
.GET()
.uri(URI.create(
"https://kubernetes.api/api/v1/namespaces/" + k8s.namespace().orElse("default") + "/configmaps?" +
"includeUninitialized=false&" +
"limit=1000&" +
"timeoutSeconds=600")
.header("Accept", "application/json")
.build(),
HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
// handle the response
IMPORTANT
|
as you can see, there is no need to pass the token to the request, it is done under the hood by the |