A small introduction to Java 11's HttpClient
Tags: java, beginners
Published: 2019-03-29 07:57:54

---
title: A small introduction to Java 11's HttpClient
published: true
description: 
tags: java, beginners
cover_image: https://www.mednikov.net/wp-content/uploads/2019/03/cliff-daylight-fog-1647962.jpg
---

Micro Java frameworks, like Spark, often lack a built-in HTTP client, so if your code need to access and consume an external [API](https://www.mednikov.tech/two-factor-authentication-for-spring-webflux-apis/) - bring your own client, like Apache, Okhttp or Unirest. This goes same way for [rare] non-web Java apps. Of course, there is _HttpURLConnection_ - available since Java 1.0 - old, low-level and not feature-rich, but... 

Java 9 introduced - in an _incubator mode_ - and Java 11 introduced finally - new built-in HTTP client. Is it worth to use? 

In this post we would see how to add HTTP Client to your app and how to proceed HTTP requests synchronously/asynchronously. 

## Overview of Java 11 HTTP Client 

The new Java HTTP client is available as a part of _java.net.http_ package and has three core components:

- __java.net.HttpClient__ - a client itself, used to send requests and retrieve response. Created via _builder_
- __java.net.HttpRequest__ - an HTTP request, created via _builder_
- __java.net.HttpResponse__ - a response. Not created directly, but is a result of sending an _HttpRequest_.

It is worth to mention that now Java supports out-of-the-box both synchronous and asynchronous modes, has HTTP/2 + legacy HTTP/1 support and has WebSocket client as well. By the way, this is a good and simple way to [test web servers in Java](https://www.mednikov.net/tutorials/start-with-vertx-junit5-at-no-time/).

## HTTP requests

Before we could do requests, we should obtain _HttpClient_ instance:

```java
/* create with default settings */
var defaultClient = HttpClient.newHttpClient();
        
/* create a custom client */
var customClient = HttpClient.newBuilder()
                    .followRedirects(Redirect.SAME_PROTOCOL)
                    .authenticator(Authenticator.getDefault())
                    .connectTimeout(Duration.ofSeconds(30))
                    .priority(1)
                    .version(HttpClient.Version.HTTP_2)
                    .build();

```

There are two ways to create _HttpClient_ - with default settings or with custom parameters. The complete list of parameters lives in [java docs](https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpClient.html), but here are some most common parameters:

- version = default value is HTTP/2, but if you need it, you can explicitly set HTTP/1.1
- connectTimeout = determines how long the client waits until a connection can be established
- followRedirects = a default value is __NEVER__.

Next step is to create _requests_. Let see how to work with them in both sync and async ways:

### Send GET in sync way

Send requests synchronously is a simple and straightforward process. We create _HttpRequest_ and then send it via _HttpClient_ and obtain _HttpResponse_ as a result. Take a look on a code snippet, it is pretty self-explanatory:

```java
var client = HttpClient.newHttpClient();

var request = HttpRequest.newBuilder().GET().uri(URI.create("https://jsonplaceholder.typicode.com/posts/1")).build();
```

We use [JSONPlaceholder](http://jsonplaceholder.typicode.com/) - fake online REST API for testing. Note, that both client and request are immutable and we can reuse them for executing multiple times. First, let see how to get data in synchronous manner:

```java
//sync
var response = client.send(request, HttpResponse.BodyHandlers.ofString());

String body = response.body();

System.out.println(body);
```

### Send GET in async way

A possibility to execute requests in asynchronous way - is one of best innovations of new API. Actually, such operations __should be performed__ in a non-blocking manner. Let see the code first:

```java
//async
var future = client.sendAsync(request, HttpResponse.BodyHandlers.ofString());

String body2 = future.thenApply(HttpResponse::body).get();

System.out.println(body2);
```

API uses [CompletableFuture](https://www.baeldung.com/java-completablefuture) - that may be explicitly completed - in order to send request asynchronously. After execution we can retrieve a data or use lambda expression to do something with response, for instance:

```java
future.thenAccept(this::processResponse);

//...

void processResponse(HttpResponse<String> response){
	//do something
}
```

### Send POST in sync way

Now, let try to send __POST__ request. Differences are that we need to specify _body_ and set POST method:

```java
//...client

//body
String body = "{}"

//create a request
var request = HttpRequest.newBuilder()
                .POST(HttpRequest.BodyPublishers.ofString(body))
                .uri(URI.create("https://jsonplaceholder.typicode.com/posts")).build();
```

Now we simple send POST request and retrieve its status code:

```java
var response = client.send(request, HttpResponse.BodyHandlers.ofString());

int code1 = response.statusCode();

System.out.printf("SYNC Status code: %d",code1);
```

### Send POST in async way

Much better idea is to send HTTP requests in asynchronous way:

```java
var future =  client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
int code2 = future.get().statusCode();
System.out.printf("ASYNC Status code: %d",code2);
```

As you can note, the principle is same as with GET (or any other) method. We create _CompletableFuture_ and then get a data from obtained _HttpResponse_ result.

## Conclusion

In this short post we observed what Java 11 HttpClient is and how to use it: create, send requests in sync/async ways. It is a quite powerful tool, you could use in your applications, when you need to work with API. 

By the way, you can also read my other posts on JVM-related topics in [my blog](https://mednikov.net) :)