Until Java 11 , making HTTP requests was not intuitive . You had to use the non friendly URLConnection class.
With Java 11 , it looks easier and cool.
To make any HTTP request ,you need the following:
- A HTTP Request
- A HTTP response
- A HTTP client to send the request and get the response
Java 11 provides exactly these three objects to make a HTTP request.
Making a GET Request:
Here is a sample get request:
(I deployed a collection of simple GET and POST rest services in my localhost and invoked them through Java 11’s HTTP client)
HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest .newBuilder() .uri(URI.create("http://localhost:8080/getData")) .build(); HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
STEP 1: Create a HTTP client
This can be done using HTTPClient class and using the newHttpClient() factory method:
STEP 2: Create a http request
To make a http request you need the request and Java 11 allows you to build this in fluent API style using builder pattern:
HttpRequest request = HttpRequest .newBuilder() .uri(URI.create("http://localhost:8080/getData")) .build();
You create a new http request builder using the factory method newBuilder() and then add method chains to it.
You specify the uri using uri() method. The URI can be created using URI.create() API
And finally you call build() method on the method chain to build the request
STEP 3: Get the HTTP response
Finally you get the HTTP response using the HTTP client object.
Here is the client call:
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
You use send() method of the HTTP client object and pass in the request and the response type.
The response type is specified using BodyHandlers class.
I am returning a string from /getData API and hence used the response type BodyHandlers.ofString()
Running the above code snippet produced the output “Hello Http Client” which I had returned through /getData API.
Making a POST request:
Let’s look at how to do a POST call now.
Let’s also see how to pass a JSON request and get back a JSON response , the most common form of HTTP exchange these days.
The algorithm is the same , only the http request differs:
Map<String, String> jsonInput = new HashMap<String, String>(); jsonInput.put("message", "This is a post call"); jsonInput.put("technology", "Java 11 Http Client"); String inputData = new ObjectMapper().writeValueAsString(jsonInput); HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://localhost:8080/sendData")) .setHeader("Content-Type", "application/json") .POST(BodyPublishers.ofString(inputData)) .build(); HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
I am preparing a map as input in the above code snippet which is equivalent to a JSON request in Java.
The HTTP client is built in the same way as in GET request using the factory method newHttpClient()
As for building the HTTP request ,
You need to specify the content type as JSON using setHeader() method
You need to specify that it is a POST request using POST() method and pass the input as a parameter. BodyPublishers class is used to build the HTTP body with the string input. You can also fetch the json input from a json file using BodyPublishers.ofFile() method.
In the above case the map input is converted to a string using Jackson API.
Finally you call build() method on the request to prepare the final HTTP request object
Once the request is built call the send() method on the HTTP client object the same way as in GET call. The response type is set to a string here as well though the API invoked returns a JSON.
It is automatically mapped to a string .
Once retrieved you can use Jackson API to convert it to a map .
Making a POST request to a Basic Authenticated service:
Now let’s see how to invoke a rest service protected by basic authentication.
Let me invoke a GET service protected by Basic Auth.
The algorithm is the same as show in the first code snippet except that you pass an authorization header.
You can do that using header() method on the HTTP request builder and pass in “Authorization” key and its value as parameters to it.
Here is the code snippet:
String username = "admin"; String password = "admin"; byte encodedBytes = Base64.getEncoder().encode((username + ":" + password).getBytes()); HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("http://localhost:8080/getProtectedData")) .header("Authorization","Basic "+new String(encodedBytes)) .build(); HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
First you encode the user name and password using Base64 encoder (Since Java 8 , Java provides a library for this) .
Then you pass it along with the header as shown above using header() method:
.header("Authorization","Basic "+new String(encodedBytes))
So easy to make HTTP calls using core java now!
In addition all the HTTP methods can be called asynchronously by calling the method sendAsync() on HTTP client. They return a CompletableFuture response which is a part of the concurrent library in java. Let me defer to another post to explore those async calls.
I have been using RestTemplate of Spring framework in my projects to make HTTP calls.
I can say for sure that Java ‘s native HTTP client looks much more intuitive and cooler than Spring framework’s HTTP Client!