Skip to content

Commit 5f4af85

Browse files
authored
[http-client] Update README.md (#434)
The loom stuff is cool, but not exactly up to date since it was done on JDK 17
1 parent c5d2438 commit 5f4af85

File tree

1 file changed

+11
-143
lines changed

1 file changed

+11
-143
lines changed

http-client/README.md

Lines changed: 11 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
1-
[![Build](https://github.com/avaje/avaje-http-client/actions/workflows/build.yml/badge.svg)](https://github.com/avaje/avaje-http-client/actions/workflows/build.yml)
1+
[![Build](https://github.com/avaje/avaje-http/actions/workflows/build.yml/badge.svg)](https://github.com/avaje/avaje-http-client/actions/workflows/build.yml)
22
[![Maven Central](https://img.shields.io/maven-central/v/io.avaje/avaje-http-client.svg?label=Maven%20Central)](https://mvnrepository.com/artifact/io.avaje/avaje-http-client)
33
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/avaje/avaje-http-client/blob/master/LICENSE)
44

55
# [Avaje-HTTP-Client](https://avaje.io/http-client/)
66

77
A lightweight wrapper to the [JDK 11+ Java Http Client](http://openjdk.java.net/groups/net/httpclient/intro.html)
88

9-
- Use Java 11.0.8 or higher (some SSL related bugs prior to 11.0.8 with JDK HttpClient)
10-
- Adds a fluid API for building URL and payload
11-
- Adds JSON marshalling/unmarshalling of request and response using Jackson or Gson
9+
- Requires Java 11+
10+
- Adds a fluid API for building URLs and payloads
11+
- Adds JSON marshalling/unmarshalling of request/response using avaje-jsonb, Jackson, Moshi, or Gson
1212
- Gzip encoding/decoding
1313
- Logging of request/response logging
1414
- Interception of request/response
15-
- Built in support for authorization via Basic Auth and Bearer Token
15+
- Built in support for authorization via Basic Auth and Bearer Tokens
1616
- Provides async and sync API
1717

18-
1918
### Dependency
2019

2120
```xml
@@ -60,13 +59,6 @@ From HttpClient:
6059
- Async processing of the request using CompletableFuture
6160
- a bean, list of beans, stream of beans, String, Void or any JDK Response.BodyHandler
6261

63-
64-
65-
## Limitations:
66-
- No support for POSTing multipart-form currently
67-
- Retry (when specified) does not apply to `async` response processing`
68-
69-
7062
## JDK HttpClient
7163

7264
- Introduction to JDK HttpClient at
@@ -75,7 +67,6 @@ From HttpClient:
7567
- Javadoc for JDK
7668
[HttpClient](https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpClient.html)
7769

78-
7970
#### Example GET as String
8071
```java
8172
HttpClient client = HttpClient.builder()
@@ -172,7 +163,7 @@ Overview of response types for sync calls.
172163
### HttpResponse BodyHandlers
173164

174165
JDK HttpClient provides a number of [BodyHandlers](https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpResponse.BodyHandler.html)
175-
including reactive Flow based subscribers. With the `handler()` method we can use any of these or our own [`HttpResponse.BodyHandler`](https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpResponse.BodyHandler.html)
166+
including reactive Flow-based subscribers. With the `handler()` method we can use any of these or our own [`HttpResponse.BodyHandler`](https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpResponse.BodyHandler.html)
176167
implementation.
177168

178169
Refer to [HttpResponse.BodyHandlers](https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpResponse.BodyHandlers.html)
@@ -198,8 +189,6 @@ When sending body content we can use:
198189
- formParams() for url encoded form (`application/x-www-form-urlencoded`)
199190
- Any [HttpRequest.BodyPublisher](https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpRequest.BodyPublishers.html)
200191

201-
202-
203192
## Examples
204193

205194
#### GET as String
@@ -345,7 +334,7 @@ HttpResponse<Void> res = client.request()
345334
assertThat(res.statusCode()).isEqualTo(201);
346335
```
347336

348-
## Retry (Sync Requests Only)
337+
## Retry
349338
To add Retry funtionality, use `.retryHandler(yourhandler)` on the builder to provide your retry handler. The `RetryHandler` interface provides two methods, one for status exceptions (e.g. you get a 4xx/5xx from the server) and another for exceptions thrown by the underlying client (e.g. server times out or client couldn't send request). Here is example implementation of `RetryHandler`.
350339

351340
```
@@ -382,7 +371,7 @@ public final class ExampleRetry implements RetryHandler {
382371
## Async processing
383372

384373
All async requests use JDK httpClient.sendAsync(...) returning CompletableFuture. Commonly the
385-
`whenComplete()` callback will be used to process the async responses.
374+
`whenComplete()` callback is used to process the async responses.
386375

387376
The `bean()`, `list()` and `stream()` responses throw a `HttpException` if the status code >= 300
388377
(noting that by default redirects are followed apart for HTTPS to HTTP).
@@ -521,10 +510,9 @@ call.async()
521510
});
522511
```
523512

524-
525513
## BasicAuthIntercept - Authorization Basic / Basic Auth
526514

527-
We can use `BasicAuthIntercept` to intercept all requests adding a `Authorization: Basic ...`
515+
We can use `BasicAuthIntercept` to intercept all requests by adding an `Authorization: Basic ...`
528516
header ("Basic Auth").
529517

530518
##### Example
@@ -541,7 +529,7 @@ HttpClient client =
541529

542530
## AuthTokenProvider - Authorization Bearer token
543531

544-
For Authorization using `Bearer` tokens that are obtained and expire, implement `AuthTokenProvider`
532+
For authorization using `Bearer` tokens that are obtained and expire, implement `AuthTokenProvider`
545533
and register that when building the HttpClient.
546534

547535
### 1. Implement AuthTokenProvider
@@ -580,124 +568,4 @@ and register that when building the HttpClient.
580568

581569
All requests using the HttpClient will automatically get
582570
an `Authorization` header with `Bearer` token added. The token will be
583-
obtained for initial request and then renewed when the token has expired.
584-
585-
586-
# 10K requests - Loom vs Async
587-
588-
The following is a very quick and rough comparison of running 10,000 requests
589-
using `Async` vs `Loom`.
590-
591-
The intention is to test the thought that in a "future Loom world" the
592-
desire to use `async()` execution with HttpClient reduces.
593-
594-
TLDR: Caveat, caveat, more caveats ... initial testing shows Loom to be just a
595-
touch faster (~10%) than async.
596-
597-
To run my tests I use [Jex](https://github.com/avaje/avaje-jex) as the server
598-
(Jetty based) and have it running using Loom. For whatever testing you do
599-
you will need a server that can handle a very large number of concurrent requests.
600-
601-
The Loom blocking request (make 10K of these)
602-
603-
```java
604-
HttpResponse<String> hres = httpClient.request()
605-
.path("s200")
606-
.GET()
607-
.asString();
608-
```
609-
The equivalent async request (make 10K of these joining the CompletableFuture's).
610-
611-
```java
612-
CompletableFuture<HttpResponse<String>> future = httpClient.request()
613-
.path("s200")
614-
.GET()
615-
.async()
616-
.asString()
617-
.whenComplete((hres, throwable) -> {
618-
...
619-
});
620-
```
621-
622-
623-
### 10K requests using Async and reactive streams
624-
625-
Use `.async()` to execute the requests which internally is using JDK
626-
HttpClient's reactive streams. The `whenComplete()` callback is invoked
627-
when the response is ready. Collect all the resulting CompletableFuture
628-
and wait for them all to complete.
629-
630-
Outline:
631-
632-
```java
633-
634-
// Collect all the CompletableFuture's
635-
List<CompletableFuture<HttpResponse<String>>> futures = new ArrayList<>();
636-
637-
for (int i = 0; i < 10_000; i++) {
638-
futures.add(httpClient.request().path("s200")
639-
.GET()
640-
.async().asString()
641-
.whenComplete((hres, throwable) -> {
642-
// confirm 200 response etc
643-
...
644-
}));
645-
}
646-
647-
// wait for all requests to complete via join() ...
648-
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
649-
650-
```
651-
652-
### 10K requests using Loom
653-
654-
With Loom Java 17 EA Release we can use `Executors.newVirtualThreadExecutor()`
655-
to return an ExecutorService that uses Loom Virtual Threads. These are backed
656-
by "Carrier threads" (via ForkedJoinPool).
657-
658-
Outline:
659-
660-
```java
661-
662-
// use Loom's Executors.newVirtualThreadExecutor()
663-
664-
try (ExecutorService executorService = Executors.newVirtualThreadExecutor()) {
665-
for (int i = 0; i < 10_000; i++) {
666-
executorService.submit(this::task);
667-
}
668-
}
669-
670-
```
671-
```java
672-
private void task() {
673-
HttpResponse<String> hres =
674-
httpClient.request().path("s200")
675-
.GET()
676-
.asString();
677-
678-
// confirm 200 response etc
679-
...
680-
}
681-
682-
```
683-
684-
Caveat: Proper performance benchmarks are really hard and take a lot of
685-
effort.
686-
687-
Running some "rough/approx performance comparison tests" using `Loom`
688-
build `17 EA 2021-09-14 / (build 17-loom+7-342)` vs `Async` for my environment
689-
and 10K request scenarios has loom execution around 10% faster than async.
690-
691-
It looks like Loom and Async run in pretty much the same time although it
692-
currently looks that Loom is just a touch faster (perhaps due to how it does
693-
park/unpark). More investigation required.
694-
695-
696-
Date: 2021-06
697-
Build: `17 EA 2021-09-14 / (build 17-loom+7-342)`.
698-
699-
```
700-
openjdk version "17-loom" 2021-09-14
701-
OpenJDK Runtime Environment (build 17-loom+7-342)
702-
OpenJDK 64-Bit Server VM (build 17-loom+7-342, mixed mode, sharing)
703-
```
571+
obtained for the initial request and then renewed when the token has expired.

0 commit comments

Comments
 (0)