Skip to Content
Course content

219: Building a REST Client Using HttpClient

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Up until now, we've focused on what happens inside our own JVM. But in the real world, your Java apps aren't islands; they need to talk to other services. For a long time, Java's built-in tools for this were... let's just say "clunky." Then Java 11 gave us java.net.http.HttpClient, and it changed the game. It's asynchronous, supports HTTP/2, and actually feels like it was written in this century.

To show you how it works, we're going to build a small client that fetches a random programming joke from a public API. It's a simple GET request, but it covers the core plumbing you'll use in almost every professional project.

Initializing the Engine

The first thing we need is the HttpClient itself. I usually treat this as a singleton or a long-lived object. You don't want to instantiate a new client for every single request—that's a waste of resources and can lead to socket exhaustion.

HttpClient client = HttpClient.newBuilder()
    .followRedirects(HttpClient.Redirect.NORMAL)
    .build();

I added followRedirects(Redirect.NORMAL) here because APIs occasionally move their endpoints. If you don't set this, you'll just get a 301 or 302 response and your code will think it failed to get the data.

Defining the Target

Now we need to tell the client where to go and what to do. We use the HttpRequest builder for this. We'll target the "Official Joke API," which is great for testing because it doesn't require an API key.

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://official-joke-api.appspot.com/random_joke"))
    .GET() // This is the default, but I like being explicit
    .header("Accept", "application/json")
    .build();

The "Oops" Moment: Ignoring the Clock

Here is where I almost tripped up. When I first wrote this snippet, I just sent the request and waited. But in a production environment, that's a recipe for disaster. If the API server hangs or the network gets flaky, your thread will sit there forever, potentially locking up your entire application.

I realized I forgot to set a timeout. You should always set a timeout on both the client and the request. Let's fix that by adding a duration to the request builder:

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://official-joke-api.appspot.com/random_joke"))
    .timeout(Duration.ofSeconds(10)) // Don't wait forever!
    .GET()
    .build();

Executing and Capturing the Body

Finally, we send the request. We have two choices: send it synchronously (blocking) or asynchronously. For this example, we'll keep it simple and go synchronous using send(). We need to tell Java how to handle the response body—in this case, we just want it as a String.

try {
    HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
    
    if (response.statusCode() == 200) {
        System.out.println("Joke received: " + response.body());
    } else {
        System.out.println("Server returned an error: " + response.statusCode());
    }
} catch (IOException | InterruptedException e) {
    e.printStackTrace();
}

I'm using HttpResponse.BodyHandlers.ofString() because it's the most straightforward way to get the raw JSON. In a larger project, you'd likely pass this string into a library like Jackson or Gson to map it to a Java object, but the HttpClient's job ends once it delivers that string to you.

Putting it all together

Here is the complete, corrected logic. Notice how the flow moves from the Client (the engine) to the Request (the instructions) to the Response (the result).

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class JokeClient {
    public static void main(String[] args) {
        HttpClient client = HttpClient.newBuilder()
            .followRedirects(HttpClient.Redirect.NORMAL)
            .build();

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://official-joke-api.appspot.com/random_joke"))
            .timeout(Duration.ofSeconds(10))
            .header("Accept", "application/json")
            .GET()
            .build();

        try {
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            System.out.println("Status: " + response.statusCode());
            System.out.println("Body: " + response.body());
        } catch (Exception e) {
            System.err.println("Request failed: " + e.getMessage());
        }
    }
}



📋 Practical Task

Exercise: Building a GitHub Profile Fetcher

Now it's your turn. Instead of a random joke, I want you to build a client that fetches public information about a GitHub user.

  • Use the GitHub Public API endpoint: https://api.github.com/users/{username} (replace {username} with your own GitHub handle or any known user like octocat).
  • Requirement: GitHub's API requires a User-Agent header. If you don't provide one, they will reject the request with a 403 Forbidden error. Use .header("User-Agent", "Java-HttpClient-Lesson") in your request builder.
  • Implement a timeout of 5 seconds.
  • Print the status code and the raw JSON body to the console.
  • Ensure your code handles IOException and InterruptedException appropriately.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.