@@ -4,7 +4,11 @@ A light weight wrapper to the JDK 11+ Java Http Client
44
55- Adds a fluid API for request constructing URL and payload
66- Adds JSON marshalling/unmarshalling of request and response using Jackson or Gson
7- - Adds request/response logging
7+ - Gzip encoding/decoding
8+ - Logging of request/response logging
9+ - Interception of request/response
10+ - Built in support for authorization via Basic Auth and Bearer Token
11+
812
913
1014
@@ -35,44 +39,130 @@ Create a HttpClientContext with a baseUrl, Jackson or Gson based JSON
3539
3640```
3741
38- ### Requests
42+ ## Requests
3943
4044From HttpClientContext:
4145 - Create a request
4246 - Build the url via path(), matrixParam(), queryParam()
4347 - Optionally set headers(), cookies() etc
44- - Optionally specify a request body (JSON, form, or raw BodyPublisher)
48+ - Optionally specify a request body (JSON, form, or any JDK BodyPublisher)
4549 - Http verbs - GET(), POST(), PUT(), PATCH(), DELETE(), HEAD(), TRACE()
46- - Optionally return response body as a bean, list of beans, stream of beans or various raw response types
47- - Optionally use Async processing of the request
50+
51+ - Sync processing response body as:
52+ - a bean, list of beans, stream of beans, String, Void or any JDK Response.BodyHandler
53+
54+ - Async processing of the request using CompleteableFuture
55+ - a bean, list of beans, stream of beans, String, Void or any JDK Response.BodyHandler
56+
57+
58+
59+ ## Limitations:
60+ - NO support for POSTing multipart-form currently
61+
62+
63+ #### Example GET as String
64+ ``` java
65+ HttpResponse<String > hres = clientContext. request()
66+ .path(" hello" )
67+ . GET ()
68+ .asString();
69+ ```
70+
71+
72+ ## Overview of responses
73+
74+ Overview of response types for sync calls.
75+
76+ <table style =" width :100% ;" >
77+ <tr ><td ><b >sync processing</b ></td ><td >  ; </td ></tr >
78+ <tr ><td >asVoid</td ><td >HttpResponse< ; Void> ; </td ></tr >
79+ <tr ><td >asString</td ><td >HttpResponse< ; String> ; </td ></tr >
80+ <tr ><td >bean< ; E> </td ><td >E</td ></tr >
81+ <tr ><td >list< ; E> </td ><td >List< ; E> ; </td ></tr >
82+ <tr ><td >stream< ; E> </td ><td >Stream< ; E> ; </td ></tr >
83+ <tr ><td >withHandler(HttpResponse.BodyHandler< ; E> ; )</td ><td >E</td ></tr >
84+ <tr ><td >  ; </td ><td >  ; </td ></tr >
85+ <tr ><td ><b >async processing</b ></td ><td >  ; </td ></tr >
86+ <tr ><td >asVoid</td ><td >CompleteableFuture< ; Void> ; </td ></tr >
87+ <tr ><td >asString</td ><td >CompleteableFuture< ; String> ; </td ></tr >
88+ <tr ><td >bean< ; E> </td ><td >CompleteableFuture< ; E> ; </td ></tr >
89+ <tr ><td >list< ; E> </td ><td >CompleteableFuture< ; List< ; E> ;> ; </td ></tr >
90+ <tr ><td >stream< ; E> </td ><td >CompleteableFuture< ; Stream< ; E> ;> ; </td ></tr >
91+ <tr ><td >withHandler(HttpResponse.BodyHandler< ; E> )</td ><td >CompleteableFuture< ; E> ; </td ></tr >
92+ </table >
93+
94+ ### JDK BodyHandlers
95+
96+ JDK HttpClient provides a number of BodyHandlers including reactive Flow based subscribers.
97+ With the ` withHandler() ` methods we can use any of these or our own ` HttpResponse.BodyHandler `
98+ implementation.
99+
100+ Reference https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpResponse.BodyHandlers.html
101+
102+ <table style =" width :100% ;" >
103+ <tr ><td >discarding()</td ><td >Discards the response body</td ></tr >
104+ <tr ><td >ofByteArray()</td ><td >byte[]</td ></tr >
105+ <tr ><td >ofString()</td ><td >String, additional charset option</td ></tr >
106+ <tr ><td >ofLines()</td ><td >Stream< ; String> ; </td ></tr >
107+ <tr ><td >ofInputStream()</td ><td >InputStream</td ></tr >
108+
109+ <tr ><td >ofFile(Path file)</td ><td >Path with various options</td ></tr >
110+ <tr ><td >ofByteArrayConsumer(...)</td ><td >  ; </td ></tr >
111+ <tr ><td >fromSubscriber</td ><td >various options</td ></tr >
112+ <tr ><td >fromLineSubscriber</td ><td >various options</td ></tr >
113+ </table >
48114
49115## Examples
50116
51- GET as String
117+ #### GET as String
52118``` java
53119HttpResponse<String > hres = clientContext. request()
54120 .path(" hello" )
55121 . GET ()
56122 .asString();
57123```
58124
59- GET as json to single bean
125+ #### Async GET as String
126+ - All async requests use JDK httpClient.sendAsync(...) returning CompleteableFuture< ; T> ;
127+ - throwable is a CompletionException
128+ - In the example below hres is of type HttpResponse< ; String> ;
129+
130+ ``` java
131+ clientContext. request()
132+ .path(" hello" )
133+ . GET ()
134+ .async(). asString()
135+ .whenComplete((hres, throwable) - > {
136+
137+ if (throwable != null ) {
138+ // CompletionException
139+ ...
140+ } else {
141+ // HttpResponse<String>
142+ int statusCode = hres. statusCode();
143+ String body = hres. body();
144+ ...
145+ }
146+ });
147+ ```
148+
149+ #### GET as json to single bean
60150``` java
61151Customer customer = clientContext. request()
62152 .path(" customers" ). path(42 )
63153 . GET ()
64154 .bean(Customer . class);
65155```
66156
67- GET as json to a list of beans
157+ #### GET as json to a list of beans
68158``` java
69159List<Customer > list = clientContext. request()
70160 .path(" customers" )
71161 . GET ()
72162 .list(Customer . class);
73163```
74164
75- GET as ` application/x-json-stream ` as a stream of beans
165+ #### GET as ` application/x-json-stream ` as a stream of beans
76166``` java
77167Stream<Customer > stream = clientContext. request()
78168 .path(" customers/all" )
@@ -81,12 +171,12 @@ Stream<Customer> stream = clientContext.request()
81171```
82172
83173
84- POST a bean as json request body
174+ #### POST a bean as json request body
85175``` java
86- HelloDto bean = new HelloDto ( 12 , " rob" , " other" );
176+ Hello bean = new Hello ( 42 , " rob" , " other" );
87177
88178HttpResponse<Void > res = clientContext. request()
89- .path(" hello/savebean " )
179+ .path(" hello" )
90180 .body(bean)
91181 . POST ()
92182 .asDiscarding();
@@ -95,7 +185,11 @@ assertThat(res.statusCode()).isEqualTo(201);
95185```
96186
97187
98- Path
188+ #### Path
189+
190+ Multiple calls to ` path() ` append with a ` / ` . This is make it easier to build a path
191+ programmatically and also build paths that include ` matrixParam() `
192+
99193``` java
100194HttpResponse<String > res = clientContext. request()
101195 .path(" customers" )
@@ -112,27 +206,29 @@ HttpResponse<String> res = clientContext.request()
112206 .asString();
113207```
114208
115- MatrixParam
209+ #### MatrixParam
116210``` java
117211HttpResponse<String > httpRes = clientContext. request()
118212 .path(" books" )
119213 .matrixParam(" author" , " rob" )
120214 .matrixParam(" country" , " nz" )
121215 .path(" foo" )
122216 .matrixParam(" extra" , " banana" )
123- . GET (). asString();
217+ . GET ()
218+ .asString();
124219```
125220
126- QueryParam
221+ #### QueryParam
127222``` java
128223List<Product > beans = clientContext. request()
129224 .path(" products" )
130225 .queryParam(" sortBy" , " name" )
131226 .queryParam(" maxCount" , " 100" )
132- . GET (). list(Product . class);
227+ . GET ()
228+ .list(Product . class);
133229```
134230
135- FormParam
231+ #### FormParam
136232``` java
137233HttpResponse<Void > res = clientContext. request()
138234 .path(" register/user" )
@@ -146,10 +242,21 @@ HttpResponse<Void> res = clientContext.request()
146242assertThat(res. statusCode()). isEqualTo(201 );
147243```
148244
149- ## Currently, NO support for POSTing multipart-form
245+
150246
151247## Async processing
152248
249+ All async requests use JDK httpClient.sendAsync(...) returning CompleteableFuture< ; T> ;
250+
251+ <table style =" width :100% ;" >
252+ <tr ><td >asVoid</td ><td >CompleteableFuture< ; Void> ; </td ></tr >
253+ <tr ><td >asString</td ><td >CompleteableFuture< ; String> ; </td ></tr >
254+ <tr ><td >bean< ; E> </td ><td >CompleteableFuture< ; E> ; </td ></tr >
255+ <tr ><td >list< ; E> </td ><td >CompleteableFuture< ; List< ; E> ;> ; </td ></tr >
256+ <tr ><td >stream< ; E> </td ><td >CompleteableFuture< ; Stream< ; E> ;> ; </td ></tr >
257+ <tr ><td >withHandler(HttpResponse.BodyHandler< ; E> )</td ><td >CompleteableFuture< ; E> </td ></tr >
258+ </table >
259+
153260### .async().asDiscarding() - HttpResponse< ; Void> ;
154261
155262``` java
@@ -214,7 +321,7 @@ clientContext.request()
214321
215322```
216323
217- ### .async().withHandler(...) - Any response body handler
324+ ### .async().withHandler(...) - Any ` Response.BodyHandler ` implementation
218325
219326The example below is a line subscriber processing response content line by line.
220327
@@ -230,6 +337,7 @@ CompletableFuture<HttpResponse<Void>> future = clientContext.request()
230337 }
231338 @Override
232339 public void onNext (String item ) {
340+ // process the line of response content
233341 ...
234342 }
235343 @Override
@@ -248,10 +356,27 @@ CompletableFuture<HttpResponse<Void>> future = clientContext.request()
248356
249357```
250358
359+ ## BasicAuthIntercept - Authorization Basic / Basic Auth
360+
361+ We can use ` BasicAuthIntercept ` to intercept all requests adding a ` Authorization: Basic ... `
362+ header ("Basic Auth").
363+
364+ ##### Example
365+
366+ ``` java
367+ HttpClientContext clientContext =
368+ HttpClientContext . newBuilder()
369+ .withBaseUrl(baseUrl)
370+ ...
371+ .withRequestIntercept(new BasicAuthIntercept (" myUsername" , " myPassword" )) < ! -- HERE
372+ .build();
373+ ```
374+
251375
252- ## Auth token
376+ ## AuthTokenProvider - Authorization Bearer token
253377
254- Built in support for obtaining and setting an Authorization token.
378+ For Authorization using ` Bearer ` tokens that are obtained and expire, implement ` AuthTokenProvider `
379+ and register that when building the HttpClientContext.
255380
256381### 1. Implement AuthTokenProvider
257382
@@ -280,14 +405,13 @@ Built in support for obtaining and setting an Authorization token.
280405``` java
281406 HttpClientContext ctx = HttpClientContext . newBuilder()
282407 .withBaseUrl(" https://foo" )
283- .withBodyAdapter(new JacksonBodyAdapter (objectMapper))
284- .withRequestListener(new RequestLogger ())
408+ ...
285409 .withAuthTokenProvider(new MyAuthTokenProvider ()) < ! -- HERE
286410 .build();
287411```
288412
289413### 3. Token obtained and set automatically
290414
291- Now all requests using the HttpClientContext will automatically get
415+ All requests using the HttpClientContext will automatically get
292416an ` Authorization ` header with ` Bearer ` token added. The token will be
293- obtained when necessary .
417+ obtained for initial request and then renewed when the token has expired .
0 commit comments