The new HTTP Client API - Sip of Java
Billy Korando on June 27, 2022Need to send or receive data from a remote service over HTTP? The HTTP Client added in JDK 11 improves upon and replaces the HttpUrlConnection
API. In this article, we will explore how to use the new HttpClient and some new functionality it offers that wasn’t available with HttpUrlConnection
.
HttpClient Overview
The HTTP Client was added in JDK 11 after first being introduced as an incubator feature in JDK 9. The goal of the HTTP Client was to replace HttpUrlConnection
, which, along with having a difficult-to-use API, didn’t offer support for protocols like HTTP/2 and WebSocket.
The HTTP Client addresses these shortcomings by offering support for the HTTP/2 and WebSocket, having an easier-to-use API, and adding new functionality like support for asynchronous calls and reactive streams.
Creating a Client
A new instance of HttpClient
is created through its builder API:
HttpClient client = HttpClient.newBuilder()
.version(Version.HTTP_1_1)
.followRedirects(Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(20))
.proxy(ProxySelector.of(...))
.authenticator(Authenticator.getDefault())
.build();
newBuilder()
has methods for setting properties like; HTTP version, redirect behavior, proxies, timeout, an authenticator, and more. Once created, an HttpClient is immutable.
Creating a Request
Like HttpClient
, an HttpRequest
is also created through its builder API:
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://openjdk.org/"))
.timeout(Duration.ofSeconds(10))
.header("Content-Type",
"application/json")
.GET()
.build()
The newBuilder()
provides methods for setting properties like; URI, timeout, headers, HTTP method, and others. Like HttpClient, an HttpRequest is immutable; however, a request can be used multiple times.
##Sending Requests
Requests can be sent either as a synchronous blocking call or asynchronous non-block call.
Synchronous Requests
HttpResponse<String> response =
client.send(request,
BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
Asynchronous Requests
client.sendAsync(request,
BodyHandlers.ofString())
.thenApply(response ->
{ System.out.println
(response.statusCode());
return response;
} )
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
Reactive Streams
Asynchronous requests can also be used as a reactive stream. As a reactive stream, the HttpRequest
acts as the publisher and the HttpResponse
as the subscriber, with the corresponding methods in their classes for handling the stream:
public abstract class HttpRequest {
...
public interface BodyPublisher
extends Flow.Publisher<ByteBuffer>
{ ... }
}
public abstract class HttpResponse<T> {
...
public interface BodyHandler<T> {
BodySubscriber<T>
apply(int statusCode,
HttpHeaders responseHeaders);
}
public interface BodySubscriber<T>
extends
Flow.Subscriber<List<ByteBuffer>>
{ ... }
}
Additional Reading
Happy coding!