Java 11: HttpClient API

Java Modularity

For years, performing HTTP calls from Java meant you would use an external dependency. That has changed with Java 11, where an all-new HttpClient API is introduced to the platform.

When doing HTTP calls from Java code, you typically use an HTTP client library. Examples are the Apache HttpClient from the HttpComponents project, Square’s OkHttp or even more high-level libraries like the JAX-RS Client API. Even though these libraries are mostly fine, it does mean taking yet another dependency in your application. Can’t Java offer a basic functionality like making an HTTP request with its standard library?

It turns out you can do so using the HttpURLConnection class, which is right there in the java.net package. However, this API (which was introduced in JDK 1.1 around 1997) is no joy to use, to say the least. Many have lamented its deficiencies. Remember, the API was created before generics, enums, lambdas, and other modern features were in the Java language. I think you can see the problem.

Fortunately a new HttpClient API has been introduced in Java 11 (released September 2018). It’s much more modern, and also supports HTTP/2 and WebSocket communication. So what does it look like? Here’s the simplest possible scenario, of performing a simple GET request:

java
HttpClient client = HttpClient.newHttpClient();

HttpRequest request = 
  HttpRequest.newBuilder(URI.create("https://luminis.eu"))
             .build();
           
HttpResponse<String> response = 
  client.send(request, HttpResponse.BodyHandlers.ofString());

After creating an HttpClient instance, we create an HttpRequest (using the builder API) and pass it to the the client’s send method. Couldn’t be simpler! In addition to the request, we must also tell the send method how to interpret the response body sent by the server. For this, several pre-defined BodyHandlers are available. Here we simple turn the server’s response into a String.

The above example shows an HttpClient and request configured with their defaults. On both the client and the request builder APIs there are many possible configuration options, for example for timeouts and HTTP redirect policies. Once a client or request is built, it is immutable. These objects are thread-safe and can be safely shared throughout an application.

In this example, a synchronous (and blocking) call is performed to the HTTP server. Once the response has been completed, it’s turned into a String and wrapped in an HttpResponse object. On this response we can check things like the HTTP status code, and of course get retrieve the body with the body() method.

You can also perform asynchronous, non-blocking calls with the new HttpClient API:

java
HttpClient client = HttpClient.newHttpClient();

HttpRequest request = 
  HttpRequest.newBuilder(URI.create("https://luminis.eu"))
             .build();
           
CompletableFuture<HttpResponse<String>> response = 
  client.sendAsync(request, HttpResponse.BodyHandlers.ofString());

response.thenApply(r -> System.out.println(r.body()));

The sendAsync method returns a CompletableFuture immediately. This CompletableFuture represents the response that will be returned at a later time by the server. The rest of the program keeps running, and the HTTP request is performed on a separate thread. Once the server returns a response, the CompletableFuture is completed. You typically use the result through methods like thenApply and other combinators that let you asynchronously work with the result.

HttpClient is not just an updated version of the old HttpURLConnection API. It also supports newer standards, like HTTP/2 and WebSockets. It’s a much need upgrade to the HTTP functionalities that ship with the JDK. Although this post only scratches the surface, it should give you enough to get started and try it out yourself!

Java Modularity