DEV Community

Cover image for Http Client API in Java: The basics
Noe Lopez
Noe Lopez

Posted on • Edited on

Http Client API in Java: The basics

Overview

The new HttpClient API was introduced in Java 11. It is a replacement for the old HttpURLConnection API which was not suitable for HTTP protocol. This new API uses builder pattern and fluent API to create the required objects to communicate over the Network. It also provides the below features:

  1. Support for HTTP2 protocol.
  2. SSL encription.
  3. Synchronous and Asynchronous communication models.
  4. Support for HTTP methods.
  5. Authentication mechanism (Basic).
  6. Cookies.

The API contains three main classes:

  • HttClient is used to send multiple requests and receive the responses over the newtwork.

  • HttpRequest is an ummutable class representing an http request to be sent. It can be configured for a specific HTTP method and append the body if any.

  • HttpResponse depicts a response comming from the web server. It is returned by the HttpClient when a request is submitted. If the call is asynchronous it returns a CompletableFuture.

The steps are straightforward. First, an instance of HttpClient is created, then the HTTP request to be dispatched. Finally, the request is passed to the HttpClient send methods and a response object is returned (or CompletableFuture if the call is asynchronous).

Use Cases In Action

Without any further delay, let's take a look at some examples:

For this demo, a SpringBoot REST application will be exposing an endpoint (located in http://localhost:8080/api/v1/customers)
that allows to list/add/update/delete customers. Customer is just an ummutable POJO class with a few members. With the help of HttpClient API, we will perform CRUD operations while interacting with the service.

1. Get List of customers

The first scenario is to get a list of all customers. This is just a GET request to the customers resource URL.

HttpClient client = HttpClient
    .newBuilder()
    .connectTimeout(Duration.ofMillis(500))
    .build();
Enter fullscreen mode Exit fullscreen mode

Note that connection will time out if it is not established in half a second. Next the http request object.

HttpRequests request = HttpRequest
    .newBuilder()
    .uri(URI.create("http://localhost:8080/api/v1/customers"))
    .header("Content-Type", "application/json")
    .GET()
    .build();
Enter fullscreen mode Exit fullscreen mode

Now the communication can be done synchronous, that is, execution is blocked until the response is received.

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.printf("Status %s \n", response.statusCode());
System.out.printf("Response %s \n", response.body());
Enter fullscreen mode Exit fullscreen mode

The BodyHandlers class contains convenient methods to convert the response body data into java objects like a String.

Program Output

Status 200 
Response [
{"id":1,"name":"Joe Smith","email":"joe.smith@gmail.com","dateOfBirth":"2008-01-01"},
{"id":2,"name":"Robert Moody","email":"robert.moody@gmail.com","dateOfBirth":"1985-06-21"},
{"id":3,"name":"Jennifer Dolan","email":"jennifer.dolan@gmail.com","dateOfBirth":"1966-11-11"},
{"id":4,"name":"Christopher Farrel","email":"christopher.farrel@gmail.com","dateOfBirth":"1970-04-15"},
{"id":5,"name":"Caroline Red","email":"caroline.red@gmail.com","dateOfBirth":"1992-03-05"}
] 
Enter fullscreen mode Exit fullscreen mode

We could send the same request asynchronously invoking the sendAsynch method. This call is non-blocking and it will
return immediately a CompletableFuture.

CompletableFuture<HttpResponse<String>> responseFuture = client.sendAsync(request, HttpResponse.BodyHandlers.ofString());

responseFuture
    .thenApply(HttpResponse::body)
    .thenApply(String::toUpperCase)
    .thenAccept(System.out::println)
    .join();
Enter fullscreen mode Exit fullscreen mode

In the above pipeline, the body is extracted from the response, uppercased and printed.

Program Output

[
{"ID":1,"NAME":"JOE SMITH","EMAIL":"JOE.SMITH@GMAIL.COM","DATEOFBIRTH":"2008-01-01"},
{"ID":2,"NAME":"ROBERT MOODY","EMAIL":"ROBERT.MOODY@GMAIL.COM","DATEOFBIRTH":"1985-06-21"},
{"ID":3,"NAME":"JENNIFER DOLAN","EMAIL":"JENNIFER.DOLAN@GMAIL.COM","DATEOFBIRTH":"1966-11-11"},
{"ID":4,"NAME":"CHRISTOPHER FARREL","EMAIL":"CHRISTOPHER.FARREL@GMAIL.COM","DATEOFBIRTH":"1970-04-15"},
{"ID":5,"NAME":"CAROLINE RED","EMAIL":"CAROLINE.RED@GMAIL.COM","DATEOFBIRTH":"1992-03-05"}
]
Enter fullscreen mode Exit fullscreen mode

2. Create a new Customer

POST method will be used to create a new customer. The body must be populated with the customer data in JSON format. The BodyPublishers class provides handy methods to convert from java objects into a flow of data for sending as a request body.

HttpRequest request = HttpRequest
    .newBuilder()
    .uri(URI.create("http://localhost:8080/api/v1/customers"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"name\":\"Sonia Lamar\",\"email\":\"sonia.lamar@mail.com\",\"dateOfBirth\":\"1998-07-29\"}"))
    .build();

var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.printf("Status %s \n", response.statusCode());
System.out.printf("Location %s \n", response.headers().map().get("location"));
Enter fullscreen mode Exit fullscreen mode

Program Output

Status 201 
Location [http://localhost:8080/api/v1/customers/6] 
Enter fullscreen mode Exit fullscreen mode

3. Update a new Customer

PUT method will be used to replace entirely an existing customer. That means all fields will be changed except the id. For partial updates, like updating only the email, the PATCH method is more appropiate.

HttpRequest request = HttpRequest
    .newBuilder()
    .uri(URI.create("http://localhost:8080/api/v1/customers/4"))
    .header("Content-Type", "application/json")
    .PUT(HttpRequest.BodyPublishers.ofString("{\"name\":\"Victor Martin\",\"email\":\"victor.martin@mail.com\",\"dateOfBirth\":\"1977-04-15\"}"))
    .build();


var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.printf("Status %s \n", response.statusCode());
System.out.printf("Body %s \n", response.body());
Enter fullscreen mode Exit fullscreen mode

Program Output

Status 200 
Body {"id":4,"name":"Victor Martin","email":"victor.martin@mail.com","dateOfBirth":"1977-04-15"} 
Enter fullscreen mode Exit fullscreen mode

4. Delete a new Customer

Final scenario is to delete the customer which id is 3.

var request = HttpRequest
    .newBuilder()
    .uri(URI.create("http://localhost:8080/api/v1/customers/3"))
    .header("Content-Type", "application/json")
    .DELETE()
    .build();

var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.printf("Status %s \n", response.statusCode());
Enter fullscreen mode Exit fullscreen mode

Program Output

Status 204
Enter fullscreen mode Exit fullscreen mode

Conclusion

We learned how to use the Java HttpClient API to consume a REST web service. We performed CRUD operations using the appropiate HTTP methods and inspect the response to verify status, headers and body.

Follow up on the second part of this series and check out how to authenticate to access secured resources. Click here to learn more!

Check the code on GitHub

Top comments (0)