Http Client API in Java: The basics
Tags: java, http, beginners
Published: 2023-03-05 12:18:13

## 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.

```java
HttpClient client = HttpClient
    .newBuilder()
    .connectTimeout(Duration.ofMillis(500))
    .build();
```

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

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

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

```java
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());
```

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

Program Output

```console
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"}
] 
```

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

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

responseFuture
    .thenApply(HttpResponse::body)
    .thenApply(String::toUpperCase)
    .thenAccept(System.out::println)
    .join();
```

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

Program Output

```console
[
{"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"}
]
```

---

**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.   

```java
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"));
```

Program Output

```console
Status 201 
Location [http://localhost:8080/api/v1/customers/6] 
```

---

**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.

```java
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());
```

Program Output

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

---

**4. Delete a new Customer**

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

```java
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());
```

Program Output

```console
Status 204
``` 

---

## 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](https://dev.to/noelopez/http-client-api-in-java-part-2-75e) to learn more!

Check the code on [GitHub](https://github.com/NoeLopezSan/java-http-client)