HttpURLConnection
.Here’s how you can perform a synchronous GET request to fetch data from a server:
import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; java.net.http.HttpResponse; java.net.http.HttpHeaders; public class HttpGetExample { public static void main(String[] args) { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.example.com/data")) .build(); try { HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Status Code: " + response.statusCode()); System.out.println("Received data: " + response.body()); } catch (Exception e) { System.out.println("Error during HTTP call: " + e.getMessage()); } } }
And here’s what it looked like before this new HTTP Client, using the older HttpURLConnection
:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class HttpGetOldExample { public static void main(String[] args) { HttpURLConnection connection = null; try { URL url = new URL("https://api.example.com/data"); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); int responseCode = connection.getResponseCode(); System.out.println("Response Code: " + responseCode); BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println("Received data: " + response.toString()); } catch (IOException e) { System.out.println("Error during HTTP call: " + e.getMessage()); } finally { if (connection != null) { connection.disconnect(); } } } }
HttpURLConnection
example involves more boilerplate code. You need to manually manage the connection, specify the request method, handle the input stream, and ensure the connection is closed after receiving the response.HttpURLConnection
is more cumbersome. You need to explicitly check the HTTP response code to determine if the request was successful or if there were errors, such as a 404 or 500 server error.HttpURLConnection
requires manual setup of a BufferedReader
, reading the lines in a loop, and appending each line to a StringBuilder
to construct the full response.HttpURLConnection
is that it does not support HTTP/2 features, such as multiplexing and server push, which are supported by the new HTTP Client API.Which of the following is NOT a feature of the HTTP Client API introduced in Java 11?
import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class HttpClientExample { public static void main(String[] args) { HttpClient client = HttpClient._______(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.example.com")) ._____(); try { HttpResponse<String> response = client._____(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response status code: " + response.statusCode()); System.out.println("Response body: " + response.body()); } catch (Exception e) { e.printStackTrace(); } } }
Correct the following code snippet.
HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newRequest() .uri(URI.create("https://api.example.com/data")) .GET() .build();
We’re gonna use HTTP Client to send a GET request to the Pokémon API to retrieve information about a specific Pokémon, starting with Pikachu, then user’s choice.
PokemonFetcherApp
-class, use the HTTP Client API to send a GET-request to fetch data about Pikachu from the Pokémon API.Here you will send a POST-request to a test API that accepts user details, and then handle and display the response.
PostUserDetailsApp
-class, use the HTTP Client API to send a POST-request with a JSON payload to the ReqRes API.https://reqres.in/api/users
Content-Type
header to application/json
{"name": "James Barnes", "job": "Axolotl Masseuse"}
Answer: C) Automatic handling of cookies
Explanation: While the HTTP Client API supports both synchronous and asynchronous programming and even WebSocket communications, it does not automatically handle cookies. Developers need to manage cookies manually or use additional libraries.
import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class HttpClientExample { public static void main(String[] args) { HttpClient client = HttpClient._______(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.example.com")) ._____(); try { HttpResponse<String> response = client._____(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response status code: " + response.statusCode()); System.out.println("Response body: " + response.body()); } catch (Exception e) { e.printStackTrace(); } } }
import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class HttpClientExample { public static void main(String[] args) { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.example.com")) .build(); try { HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response status code: " + response.statusCode()); System.out.println("Response body: " + response.body()); } catch (Exception e) { e.printStackTrace(); } } }
HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newRequest() .uri(URI.create("https://api.example.com/data")) .GET() .build();
HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() // Changed from newRequest() to newBuilder() .uri(URI.create("https://api.example.com/data")) .GET() .build();
public class PokemonFetcherApp { private static final Scanner KEYBOARD = new Scanner(System.in); public static void main(String[] args) { String inputName = askForPokemonName(); HttpResponse<String> response = fetchPokemonByName(inputName); System.out.println("Status Code: " + response.statusCode()); switch (response.statusCode()) { case 200: System.out.println("Response Body: " + response.body()); break; case 404: System.out.println("No Pokémon found with that name: " + inputName); break; default: System.out.println("Something went wrong"); } } private static HttpResponse<String> fetchPokemonByName(String name) { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://pokeapi.co/api/v2/pokemon/" + name)) .build(); try{ return client.send(request, HttpResponse.BodyHandlers.ofString()); } catch (Exception e){ throw new RuntimeException(e); } } private static String askForPokemonName() { System.out.print("Enter a Pokémon name: "); String name = KEYBOARD.nextLine().trim(); while (name.isEmpty()) { System.out.print("Please enter a Pokémon name: "); name = KEYBOARD.nextLine().trim(); } return name.toLowerCase(); } }
public class PostUserDetailsApp { private static final Scanner KEYBOARD = new Scanner(System.in); public static void main(String[] args) { // Prepare the JSON payload as a String String userPayload = askForUserPayload(); HttpResponse<String> response = postUserDetails(userPayload); // Print status code and response body System.out.println("Status Code: " + response.statusCode()); System.out.println("Response Body: " + response.body()); } private static String askForUserPayload() { System.out.print("Enter name: "); String inputName = KEYBOARD.nextLine(); System.out.print("Enter job: "); String inputJob = KEYBOARD.nextLine(); return convertUserToJson(inputName, inputJob); } private static String convertUserToJson(String name, String job) { // Create a JSON object with the user details return String.format("{\"name\": \"%s\", \"job\": \"%s\"}", name, job); } private static HttpResponse<String> postUserDetails(String userPayload) { // Create the HttpRequest HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://reqres.in/api/users")) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(userPayload)) .build(); // Send the request and get the response try { return HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); } catch (IOException | InterruptedException e) { throw new RuntimeException(e); } } }
Asynchronous requests are a powerful feature of Java’s HTTP/2 Client API that allow your application to perform non-blocking operations over HTTP. This means your app can continue executing other tasks while waiting for the HTTP response.
What are Asynchronous Requests?
Why Use Asynchronous Requests?
How to Use Asynchronous Requests?
HttpClient.sendAsync()
method, which sends the HTTP request and immediately returns a CompletableFuture<HttpResponse<T>>
. This future will complete once the response is available.thenApply
, thenAccept
, or thenCombine
to handle the response once it’s received, without blocking the current thread.Here’s how to perform an asynchronous GET request with Java’s HTTP/2 Client API, incorporating error handling and response processing:
import java.net.URI; import java.net.http.HttpClient; import java.net/http.HttpRequest; import java.net/http.HttpResponse; public class HttpGetAsyncExample { public static void main(String[] args) { HttpClient client = HttpClient.newBuilder().build(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.example.com/data")) .build(); client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) .thenApply(response -> { if (response.statusCode() == 200) { return response.body(); } else { throw new RuntimeException("Failed: HTTP error code : " + response.statusCode()); } }) .exceptionally(e -> "Error: " + e.getMessage()) .thenAccept(System.out::println) .join(); // Wait for the response to ensure JVM doesn't exit prematurely } }
PostUserDetailsApp
-class, naming it PostUserDetailsAsyncApp
.main
-method with print-statements (see example screenshots).main
-method keeps being executed (even until completion), while the POST-request is sent in the background asynchronously.PokemonFetcherApp
-class, naming it PokemonFetcherAsyncApp
.public class PostUserDetailsAsyncApp { private static final Scanner KEYBOARD = new Scanner(System.in); public static void main(String[] args) { // Prepare the JSON payload as a String runAsynchronously(); System.out.println("Finished code in main-method"); } private static void runAsynchronously() { System.out.println("Running asynchronously"); String userPayload = askForUserPayload(); postUserDetailsAsync(userPayload).thenAccept(response -> handleResponse(response)).join(); } private static void runSynchronously() { System.out.println("Running synchronously"); String userPayload = askForUserPayload(); HttpResponse<String> response = postUserDetailsSync(userPayload); handleResponse(response); } private static void handleResponse(HttpResponse<String> response) { // Print status code and response body System.out.println("Status Code: " + response.statusCode()); System.out.println("Response Body: " + response.body()); } private static String askForUserPayload() { System.out.print("Enter name: "); String inputName = KEYBOARD.nextLine(); System.out.print("Enter job: "); String inputJob = KEYBOARD.nextLine(); return convertUserToJson(inputName, inputJob); } private static String convertUserToJson(String name, String job) { // Create a JSON object with the user details return String.format("{\"name\": \"%s\", \"job\": \"%s\"}", name, job); } private static HttpResponse<String> postUserDetailsSync(String userPayload) { // Create the HttpRequest HttpRequest request = preparePostUserReq(userPayload); // Send the request and get the response try { return HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); } catch (IOException | InterruptedException e) { throw new RuntimeException(e); } } private static CompletableFuture<HttpResponse<String>> postUserDetailsAsync(String userPayload) { // Create the HttpRequest HttpRequest request = preparePostUserReq(userPayload); // Send the request asynchronously and get the response return HttpClient.newHttpClient().sendAsync(request, HttpResponse.BodyHandlers.ofString()) .thenApply(res -> { if (res.statusCode() / 100 == 2) { return res; } else { throw new RuntimeException("Request failed with status code " + res.statusCode()); } }); } private static HttpRequest preparePostUserReq(String userPayload) { return HttpRequest.newBuilder() .uri(URI.create("https://reqres.in/api/users")) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(userPayload)) .build(); } }
public class PokemonFetcherAsyncApp { private static final Scanner KEYBOARD = new Scanner(System.in); public static void main(String[] args) { String[] names = {"bulbasaur", "charmander", "squirtle"}; System.out.println("▶ Synchronous test:"); runFetchPokemonsSyncTest(names); System.out.println("▶ Asynchronous test:"); runFetchPokemonsAsyncTest(names); } private static void runFetchPokemonsSyncTest(String[] names) { runTimedFunction(() -> { for (String name : names) { HttpResponse<String> response = fetchPokemonByNameSync(name); handleResponseForPokemonWithName(response, name); } }); } private static void runFetchPokemonsAsyncTest(String[] names) { runTimedFunction(() -> { // Create a list of CompletableFuture objects from the names array List<CompletableFuture<Void>> futures = Arrays.stream(names) .map(n -> fetchPokemonByNameAsync(n).thenAccept(response -> handleResponseForPokemonWithName(response, n))) .collect(Collectors.toList()); // Wait for all futures to complete CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); }); } private static void runTimedFunction(Runnable runnable) { LocalDateTime startTime = LocalDateTime.now(); runnable.run(); LocalDateTime endTime = LocalDateTime.now(); Duration duration = Duration.between(startTime, endTime); long minutes = duration.toMinutes(); long seconds = duration.minusMinutes(minutes).getSeconds(); long milliseconds = duration.minusSeconds(seconds).toMillis(); System.out.printf("\t⌚Total duration: %d minutes, %d seconds, and %d milliseconds%n", minutes, seconds, milliseconds); } private static void handleResponseForPokemonWithName(HttpResponse<String> response, String name) { System.out.print("Status Code: " + response.statusCode() + " | "); switch (response.statusCode()) { case 200: System.out.printf("'%s' successfully fetched.\n", name); break; case 404: System.out.println("No Pokémon found with that name: " + name); break; default: System.out.println("Something went wrong"); } } private static CompletableFuture<HttpResponse<String>> fetchPokemonByNameAsync(String name) { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = prepareGetPokemonByNameReq(name); // Returning a CompletableFuture<HttpResponse<String>> System.out.printf("Fetching '%s' asynchronously...%n", name); return client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) .thenApply(response -> { // You can process the response further here if needed return response; }) .exceptionally(e -> { // Exception handling logic here System.err.println("Failed to fetch data: " + e.getMessage()); throw new RuntimeException("Failed to fetch Pokemon data", e); }); } private static HttpResponse<String> fetchPokemonByNameSync(String name) { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = prepareGetPokemonByNameReq(name); try { System.out.printf("Fetching '%s' synchronously...%n", name); return client.send(request, HttpResponse.BodyHandlers.ofString()); } catch (Exception e) { throw new RuntimeException(e); } } private static HttpRequest prepareGetPokemonByNameReq(String name) { return HttpRequest.newBuilder() .uri(URI.create("https://pokeapi.co/api/v2/pokemon/" + name)) .method("GET", HttpRequest.BodyPublishers.noBody()) .build(); } private static String askForPokemonName() { System.out.print("Enter a Pokémon name: "); String name = KEYBOARD.nextLine().trim(); while (name.isEmpty()) { System.out.print("Please enter a Pokémon name: "); name = KEYBOARD.nextLine().trim(); } return name.toLowerCase(); } }
HttpURLConnection
with a modern API that supports HTTP/2 and WebSocket, enhancing efficiency and functionality. Introduced as an incubator feature in Java 9 and standardized in Java 11 under JEPs 110 and 321.HttpURLConnection
. It automates connection management, stream handling, and error processing, making the code more readable and maintainable.