Skip to content

Commit 7932157

Browse files
committed
#21 - ENH: Add HttpCall that allows client to choose async or sync processing of request
1 parent bf6a55a commit 7932157

File tree

6 files changed

+448
-0
lines changed

6 files changed

+448
-0
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package io.avaje.http.client;
2+
3+
import java.net.http.HttpResponse;
4+
import java.util.List;
5+
import java.util.concurrent.CompletableFuture;
6+
import java.util.stream.Stream;
7+
8+
class DHttpCall implements HttpCallResponse {
9+
10+
private final DHttpClientRequest request;
11+
12+
DHttpCall(DHttpClientRequest request) {
13+
this.request = request;
14+
}
15+
16+
@Override
17+
public HttpCall<HttpResponse<Void>> asDiscarding() {
18+
return new CallDiscarding();
19+
}
20+
21+
@Override
22+
public HttpCall<HttpResponse<String>> asString() {
23+
return new CallString();
24+
}
25+
26+
@Override
27+
public <E> HttpCall<HttpResponse<E>> withHandler(HttpResponse.BodyHandler<E> bodyHandler) {
28+
return new CallHandler<>(bodyHandler);
29+
}
30+
31+
@Override
32+
public <E> HttpCall<E> bean(Class<E> type) {
33+
return new CallBean<>(type);
34+
}
35+
36+
@Override
37+
public <E> HttpCall<List<E>> list(Class<E> type) {
38+
return new CallList<>(type);
39+
}
40+
41+
@Override
42+
public <E> HttpCall<Stream<E>> stream(Class<E> type) {
43+
return new CallStream<>(type);
44+
}
45+
46+
private class CallDiscarding implements HttpCall<HttpResponse<Void>> {
47+
@Override
48+
public HttpResponse<Void> execute() {
49+
return request.asVoid();
50+
}
51+
@Override
52+
public CompletableFuture<HttpResponse<Void>> async() {
53+
return request.async().asDiscarding();
54+
}
55+
}
56+
57+
private class CallString implements HttpCall<HttpResponse<String>> {
58+
@Override
59+
public HttpResponse<String> execute() {
60+
return request.asString();
61+
}
62+
@Override
63+
public CompletableFuture<HttpResponse<String>> async() {
64+
return request.async().asString();
65+
}
66+
}
67+
68+
private class CallBean<E> implements HttpCall<E> {
69+
private final Class<E> type;
70+
CallBean(Class<E> type) {
71+
this.type = type;
72+
}
73+
@Override
74+
public E execute() {
75+
return request.bean(type);
76+
}
77+
@Override
78+
public CompletableFuture<E> async() {
79+
return request.async().bean(type);
80+
}
81+
}
82+
83+
private class CallList<E> implements HttpCall<List<E>> {
84+
private final Class<E> type;
85+
CallList(Class<E> type) {
86+
this.type = type;
87+
}
88+
@Override
89+
public List<E> execute() {
90+
return request.list(type);
91+
}
92+
@Override
93+
public CompletableFuture<List<E>> async() {
94+
return request.async().list(type);
95+
}
96+
}
97+
98+
private class CallStream<E> implements HttpCall<Stream<E>> {
99+
private final Class<E> type;
100+
CallStream(Class<E> type) {
101+
this.type = type;
102+
}
103+
@Override
104+
public Stream<E> execute() {
105+
return request.stream(type);
106+
}
107+
@Override
108+
public CompletableFuture<Stream<E>> async() {
109+
return request.async().stream(type);
110+
}
111+
}
112+
113+
private class CallHandler<E> implements HttpCall<HttpResponse<E>> {
114+
private final HttpResponse.BodyHandler<E> handler;
115+
CallHandler(HttpResponse.BodyHandler<E> handler) {
116+
this.handler = handler;
117+
}
118+
@Override
119+
public HttpResponse<E> execute() {
120+
return request.withHandler(handler);
121+
}
122+
@Override
123+
public CompletableFuture<HttpResponse<E>> async() {
124+
return request.async().withHandler(handler);
125+
}
126+
}
127+
}

client/src/main/java/io/avaje/http/client/DHttpClientRequest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,11 @@ public HttpAsyncResponse async() {
289289
return new DHttpAsync(this);
290290
}
291291

292+
@Override
293+
public HttpCallResponse call() {
294+
return new DHttpCall(this);
295+
}
296+
292297
@Override
293298
public HttpClientResponse HEAD() {
294299
httpRequest = newHead(url.build());
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.avaje.http.client;
2+
3+
import java.util.concurrent.CompletableFuture;
4+
5+
/**
6+
* Allows for executing the request asynchronously or synchronously.
7+
*
8+
* @param <E> The type of response
9+
*/
10+
public interface HttpCall<E> {
11+
12+
/**
13+
* Execute the request returning the result.
14+
*/
15+
E execute();
16+
17+
/**
18+
* Execute the request asynchronously.
19+
*/
20+
CompletableFuture<E> async();
21+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package io.avaje.http.client;
2+
3+
import java.net.http.HttpResponse;
4+
import java.util.List;
5+
import java.util.stream.Stream;
6+
7+
/**
8+
* Allows the client code to choose to execute the request asynchronously
9+
* or synchronously.
10+
*/
11+
public interface HttpCallResponse {
12+
13+
/**
14+
* Process discarding response body as {@literal HttpResponse<Void>}.
15+
*
16+
* <pre>{@code
17+
*
18+
* HttpCall<HttpResponse<Void>> call =
19+
* clientContext.request()
20+
* .path("hello/world")
21+
* .GET()
22+
* .call().asDiscarding();
23+
*
24+
* }</pre>
25+
*
26+
* @return The HttpCall to allow sync or async execution
27+
*/
28+
HttpCall<HttpResponse<Void>> asDiscarding();
29+
30+
/**
31+
* Process as String response body {@literal HttpResponse<String>}.
32+
*
33+
* <pre>{@code
34+
*
35+
* HttpCall<HttpResponse<String>> call =
36+
* clientContext.request()
37+
* .path("hello/world")
38+
* .GET()
39+
* .call().asString();
40+
*
41+
* }</pre>
42+
*
43+
* @return The HttpCall to allow sync or async execution
44+
*/
45+
HttpCall<HttpResponse<String>> asString();
46+
47+
/**
48+
* Call using any given {@code HttpResponse.BodyHandler}.
49+
* <pre>{@code
50+
*
51+
* HttpCall<E> call = clientContext.request()
52+
* .path("hello/lineStream")
53+
* .GET()
54+
* .call().withHandler(HttpResponse.BodyHandler<E> ...);
55+
* }</pre>
56+
*
57+
* @param bodyHandler The response body handler to use
58+
* @return The HttpCall to allow sync or async execution
59+
*/
60+
<E> HttpCall<HttpResponse<E>> withHandler(HttpResponse.BodyHandler<E> bodyHandler);
61+
62+
/**
63+
* A bean response to execute async or sync.
64+
* <p>
65+
* If the HTTP statusCode is 300 or above a HttpException is throw which contains
66+
* the HttpResponse. This is the cause in the CompletionException. Redirects are
67+
* by default followed apart from HTTPS to HTTP.
68+
*
69+
* <pre>{@code
70+
*
71+
* HttpCall<HelloDto> call =
72+
* clientContext.request()
73+
* ...
74+
* .POST()
75+
* .call().bean(HelloDto.class);
76+
*
77+
* }</pre>
78+
*
79+
* @param type The bean type to convert the content to
80+
* @return The HttpCall to allow sync or async execution
81+
*/
82+
<E> HttpCall<E> bean(Class<E> type);
83+
84+
/**
85+
* Process expecting a list of beans response body (typically from json content).
86+
* <p>
87+
* If the HTTP statusCode is 300 or above a HttpException is throw which contains
88+
* the HttpResponse. This is the cause in the CompletionException. Redirects are
89+
* by default followed apart from HTTPS to HTTP.
90+
*
91+
* <pre>{@code
92+
*
93+
* HttpCall<List<HelloDto>> call =
94+
* clientContext.request()
95+
* ...
96+
* .GET()
97+
* .call().list(HelloDto.class);
98+
* }</pre>
99+
*
100+
* @param type The bean type to convert the content to
101+
* @return The HttpCall to execute sync or async
102+
*/
103+
<E> HttpCall<List<E>> list(Class<E> type);
104+
105+
/**
106+
* Process expecting a stream of beans response body (typically from json content).
107+
* <p>
108+
* If the HTTP statusCode is 300 or above a HttpException is throw which contains
109+
* the HttpResponse. This is the cause in the CompletionException. Redirects are
110+
* by default followed apart from HTTPS to HTTP.
111+
*
112+
* <pre>{@code
113+
*
114+
* HttpCall<Stream<HelloDto>> call =
115+
* clientContext.request()
116+
* ...
117+
* .GET()
118+
* .call().stream(HelloDto.class);
119+
* }</pre>
120+
*
121+
* @param type The bean type to convert the content to
122+
* @return The HttpCall to execute sync or async
123+
*/
124+
<E> HttpCall<Stream<E>> stream(Class<E> type);
125+
126+
}

client/src/main/java/io/avaje/http/client/HttpClientResponse.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ public interface HttpClientResponse {
1717
*/
1818
HttpAsyncResponse async();
1919

20+
/**
21+
* Return a HttpCall which allows either sync or async
22+
* execution of the request.
23+
*/
24+
HttpCallResponse call();
25+
2026
/**
2127
* Returning the response using the given response reader.
2228
*

0 commit comments

Comments
 (0)