Appearance
Lesson 01 · HTTP with java.net.http
Beyond the 1Z0-830 exam
Since Java 11, the JDK ships a modern HTTP client (java.net.http, JEP 321) — HTTP/2, builders, sync and async. You don't need a third-party library for most calls. It's the foundation under this module's lab and a clean way to talk to any REST service.
Objectives
After this lesson you will be able to:
- Build and reuse an
HttpClient. - Construct
HttpRequestobjects for GET/POST with headers and bodies. - Read an
HttpResponse— status, headers, and body viaBodyHandlers. - Choose between synchronous (
send) and asynchronous (sendAsync) calls.
The three types
The API is three immutable, builder-based types:
| Type | Role |
|---|---|
HttpClient | the reusable, thread-safe sender; owns the connection pool |
HttpRequest | one request — URI, method, headers, body |
HttpResponse<T> | the result — statusCode(), headers(), body() |
java
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(5))
.followRedirects(HttpClient.Redirect.NORMAL)
.build();Reuse the client
An HttpClient is immutable and thread-safe — build one and share it. Creating a client per request wastes connections and defeats HTTP/2 multiplexing. (Java 21 adds close()/AutoCloseable for graceful shutdown, but a long-lived client is the norm.)
A synchronous GET
java
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/widgets/1"))
.header("Accept", "application/json")
.GET() // GET is also the default
.build();
HttpResponse<String> res = client.send(request, HttpResponse.BodyHandlers.ofString());
int status = res.statusCode(); // e.g. 200
String body = res.body(); // the JSON textBodyHandlersdecide how the response body is read:ofString(),ofByteArray(),ofLines(),ofFile(path),discarding().BodyPublishersproduce the request body:ofString(json),ofFile(path),noBody().
Trap — don't confuse the two
BodyHandlers are for responses; BodyPublishers are for requests. BodyPublishers.ofString sets what you send; BodyHandlers.ofString controls what you receive. Swapping them won't compile, but the names are easy to mix up under exam-style pressure.
A POST with a body
java
HttpRequest post = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/widgets"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString("{\"name\":\"Gizmo\"}"))
.build();
HttpResponse<String> res = client.send(post, HttpResponse.BodyHandlers.ofString());PUT(...), DELETE(), and method("PATCH", publisher) round out the verbs. The client does not throw on 4xx/5xx — a 404 is a normal response. You must check statusCode() and act on it (the lab throws on a non-200, rather than silently returning a bogus object).
Asynchronous calls
sendAsync returns a CompletableFuture (Module 07) and never blocks the caller:
java
CompletableFuture<String> bodyFuture = client
.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body); // compose, don't blockUse async when firing many requests concurrently or wiring HTTP into a reactive pipeline. For a single call in a test, synchronous send is simpler and easier to assert on.
SDET note
The lab's ApiClient takes its base URL as a constructor argument. That one move lets the test point it at an in-JVM com.sun.net.httpserver.HttpServer on a random port — a real HTTP round-trip with zero network or Docker — while production points it at the live service. Same dependency injection you saw with the JDBC Connection in Module 16.
Key Takeaways
java.net.httpgives you three types:HttpClient(reuse it),HttpRequest,HttpResponse<T>.BodyHandlersread responses;BodyPublishersproduce request bodies — don't swap them.- The client doesn't throw on 4xx/5xx; check
statusCode()yourself. sendis synchronous;sendAsyncreturns aCompletableFuturefor non-blocking/concurrent calls.- Inject the base URL so tests can target a local fake server.
Lesson Quiz
How should you treat an HttpClient instance?
Which reads the RESPONSE body as a String?
What does the client do when the server returns 404?
sendAsync(...) returns…
To send a JSON request body you use…
Next: JSON Binding. This module's lab is in labs/src/main/java/com/jse21/m17_api/.