Skip to content

Commit b1d69dc

Browse files
committed
Documentation:
commit 602ffc0 Author: Tiago de Freitas Lima <[email protected]> Date: Tue May 31 10:29:41 2022 -0300 Readme/documentation from core and all modules.
1 parent ae2d1ff commit b1d69dc

File tree

31 files changed

+2205
-503
lines changed

31 files changed

+2205
-503
lines changed

README.md

+581-474
Large diffs are not rendered by default.

core/src/main/java/com/github/ljtfreitas/julian/Attempt.java

+12
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ public interface Attempt<T> {
3939

4040
Attempt<T> onFailure(Consumer<? super Throwable> fn);
4141

42+
Attempt<T> failure(Function<? super Throwable, ? extends Throwable> fn);
43+
4244
<E extends Throwable> Attempt<T> failure(Class<E> candidate, Function<? super E, ? extends Throwable> fn);
4345

4446
Attempt<T> failure(Predicate<? super Throwable> candidate, Function<? super Throwable, ? extends Throwable> fn);
@@ -124,6 +126,11 @@ public Attempt<T> onFailure(Consumer<? super Throwable> fn) {
124126
return this;
125127
}
126128

129+
@Override
130+
public Attempt<T> failure(Function<? super Throwable, ? extends Throwable> fn) {
131+
return this;
132+
}
133+
127134
@Override
128135
public <E extends Throwable> Attempt<T> failure(Class<E> candidate, Function<? super E, ? extends Throwable> fn) {
129136
return this;
@@ -228,6 +235,11 @@ public Attempt<T> recover(Predicate<? super Throwable> candidate, ThrowableSuppl
228235
return candidate.test(value) ? Attempt.run(fn) : this;
229236
}
230237

238+
@Override
239+
public Attempt<T> failure(Function<? super Throwable, ? extends Throwable> fn) {
240+
return new Failure<>(fn.apply(value));
241+
}
242+
231243
@SuppressWarnings("unchecked")
232244
@Override
233245
public <E extends Throwable> Attempt<T> failure(Class<E> candidate, Function<? super E, ? extends Throwable> fn) {

core/src/main/java/com/github/ljtfreitas/julian/Bracket.java

+5
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ public Attempt<T> recover(Predicate<? super Throwable> candidate, ThrowableSuppl
100100
return id().recover(candidate, fn);
101101
}
102102

103+
@Override
104+
public Attempt<T> failure(Function<? super Throwable, ? extends Throwable> fn) {
105+
return id().failure(fn);
106+
}
107+
103108
@Override
104109
public <E extends Throwable> Attempt<T> failure(Class<E> candidate, Function<? super E, ? extends Throwable> fn) {
105110
return id().failure(candidate, fn);

core/src/main/java/com/github/ljtfreitas/julian/http/HTTP.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,9 @@
2222

2323
package com.github.ljtfreitas.julian.http;
2424

25-
import java.net.URI;
26-
2725
import com.github.ljtfreitas.julian.Promise;
28-
import com.github.ljtfreitas.julian.http.client.HTTPClient;
26+
27+
import java.net.URI;
2928

3029
public interface HTTP {
3130

form-url-encoded-multipart/README.md

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
## form-url-encoded-multipart
2+
3+
This module provides support to `application/x-www-form-urlencoded` and `multipart/form-data` media types.
4+
5+
## Install
6+
7+
### Maven
8+
```xml
9+
<dependency>
10+
<groupId>com.github.ljtfreitas.julian-http-client</groupId>
11+
<artifactId>julian-http-client-form-url-encoded-multipart</artifactId>
12+
<version>${julian-http-client-version}</version>
13+
</dependency>
14+
```
15+
16+
### Gradle
17+
```kotlin
18+
dependencies {
19+
implementation("com.github.ljtfreitas.julian-http-client:julian-http-client-form-url-encoded-multipart:$julianHttpClientVersion")
20+
}
21+
```
22+
23+
Then, the required codecs will be registered automatically. Let's move to code :)
24+
25+
## Usage
26+
27+
### application/x-www-form-urlencoded
28+
29+
`application/x-www-form-urlencoded` can be used to send form data in a request body. This module enables some ways to do that:
30+
31+
```java
32+
import com.github.ljtfreitas.julian.Form;
33+
34+
interface MyApi {
35+
36+
// @FormUrlEncoded is an alias to @Body("application/x-www-form-urlencoded")
37+
38+
@POST("/resource")
39+
@FormUrlEncoded
40+
void sendAsForm(@Body Form form);
41+
42+
@POST("/resource")
43+
@FormUrlEncoded
44+
void sendAsMap(@Body Map<String, String> map);
45+
46+
@POST("/resource")
47+
@FormUrlEncoded
48+
void sendAsMultiMap(@Body Map<String, Collection<String>> map);
49+
}
50+
51+
MyApi myApi = new ProxyBuilder()
52+
.build(MyApi.class, "http://my.api.com");
53+
54+
// Form is a multi-map like, immutable object
55+
Form form = new Form()
56+
.join("name", "Tiago de Freitas Lima")
57+
.join("age", "36")
58+
.join("pets", "Zulu", "Puka", "Fiona"); // multiple values for the same field are valid
59+
60+
myApi.sendAdForm(form);
61+
62+
// We can use a plain Map too
63+
Map<String, String> map = new HashMap<>();
64+
map.put("name", "Tiago de Freitas Lima");
65+
map.put("age", "36");
66+
67+
myApi.sendAsMap(map);
68+
69+
// Or we can use a map with multiple values
70+
Map<String, Collection<String>> multiMap = new HashMap<>();
71+
multiMap.put("name", "Tiago de Freitas Lima");
72+
multiMap.put("age", "36");
73+
multiMap.put("pets", List.of("Zulu", "Puka, "Fiona""));
74+
75+
myApi.sendAsMultiMap(map);
76+
```
77+
78+
### multipart/form-data
79+
80+
`multipart/form-data` is the media type used to upload files as well other fields as a form.
81+
82+
We can send a multipart form using a `MultipartForm` object or a `Map`:
83+
84+
```java
85+
import com.github.ljtfreitas.julian.multipart.MultipartForm;
86+
87+
import java.io.File;
88+
import java.io.FileInputStream;
89+
import java.nio.ByteBuffer;
90+
import java.nio.file.Paths;
91+
92+
interface MyApi {
93+
94+
// @MultipartFormData is an alias to @Body("multipart/form-data")
95+
96+
@POST("/resource")
97+
@MultipartFormData
98+
void uploadAsForm(@Body MultipartForm form);
99+
100+
@POST("/resource")
101+
@MultipartFormData
102+
void sendAsMap(@Body Map<String, Object> map);
103+
}
104+
105+
MyApi myApi = new ProxyBuilder()
106+
.build(MyApi.class, "http://my.api.com");
107+
108+
// MultipartForm is a multi-map like, immutable object
109+
Form form = new MultipartForm()
110+
.join(MultipartForm.Part.create("name", "Tiago de Freitas Lima"))
111+
.join(MultipartForm.Part.create("age", "36"))
112+
.join(MultipartForm.Part.create("picture", new File("/path/to/file.jpg"))) // we can send a java.io.File
113+
.join(MultipartForm.Part.create("picture", Paths.get("/path/to/file.jpg"), "file.jpg")) // or a java.nio.file.Path
114+
.join(MultipartForm.Part.create("picture", new FileInputStream("/path/to/file.jpg"), "file.jpg")) // or a java.io.InputStream
115+
.join(MultipartForm.Part.create("picture", new byte[...], "file.jpg")) // or a byte array with the file content
116+
.join(MultipartForm.Part.create("picture", ByteBuffer.wrap(new byte[...]), "file.jpg")); // or a java.nio.ByteBuffer with the file content
117+
118+
myApi.sendAdForm(form);
119+
120+
// We can use a plain Map too
121+
Map<String, Object> map = new HashMap<>();
122+
map.put("name", "Tiago de Freitas Lima");
123+
map.put("age", "36");
124+
map.put("picture", new File("/path/to/file.jpg")); // the same types are supported: File, Path, etc...
125+
126+
myApi.sendAsMap(map);
127+
```

form-url-encoded-multipart/build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ plugins {
2525
}
2626

2727
tasks.jar.configure {
28-
archiveBaseName.set("julian-http-client-form-url-encodec-multipart")
28+
archiveBaseName.set("julian-http-client-form-url-encoded-multipart")
2929
}
3030

3131
dependencies {

form-url-encoded-multipart/src/main/java/com/github/ljtfreitas/julian/http/codec/form/SimpleMapFormURLEncodedHTTPMessageCodec.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141

4242
import static com.github.ljtfreitas.julian.http.MediaType.APPLICATION_FORM_URLENCODED;
4343

44-
public class SimpleMapFormURLEncodedHTTPMessageCodec implements FormURLEncodedHTTPMessageCodec<Map<String, String>> {
44+
public class SimpleMapFormURLEncodedHTTPMessageCodec implements FormURLEncodedHTTPMessageCodec<Map<String, ?>> {
4545

4646
private static final SimpleMapFormURLEncodedHTTPMessageCodec SINGLE_INSTANCE = new SimpleMapFormURLEncodedHTTPMessageCodec();
4747

@@ -61,12 +61,12 @@ private boolean supportedMap(JavaType javaType) {
6161
}
6262

6363
@Override
64-
public HTTPRequestBody write(Map<String, String> map, Charset encoding) {
64+
public HTTPRequestBody write(Map<String, ?> map, Charset encoding) {
6565
return new DefaultHTTPRequestBody(APPLICATION_FORM_URLENCODED, () -> serialize(map, encoding));
6666
}
6767

68-
private Publisher<ByteBuffer> serialize(Map<String, String> map, Charset encoding) {
69-
return serializer.serialize("", JavaType.parameterized(Map.class, String.class, String.class), map)
68+
private Publisher<ByteBuffer> serialize(Map<String, ?> map, Charset encoding) {
69+
return serializer.serialize("", JavaType.parameterized(Map.class, String.class, Object.class), map)
7070
.map(form -> codec.write(form, encoding).serialize())
7171
.orElseGet(BodyPublishers::noBody);
7272
}
@@ -77,7 +77,7 @@ public boolean readable(MediaType candidate, JavaType javaType) {
7777
}
7878

7979
@Override
80-
public Optional<CompletableFuture<Map<String, String>>> read(HTTPResponseBody body, JavaType javaType) {
80+
public Optional<CompletableFuture<Map<String, ?>>> read(HTTPResponseBody body, JavaType javaType) {
8181
return codec.read(body, javaType)
8282
.map(future -> future
8383
.thenApplyAsync(form -> form.all().entrySet().stream()

form-url-encoded-multipart/src/test/java/com/github/ljtfreitas/julian/http/codec/form/SimpleMapFormURLEncodedHTTPMessageCodecTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ class Read {
111111
void read() {
112112
String value = "name=Tiago&age=35";
113113

114-
Map<String, String> form = codec.read(HTTPResponseBody.some(value.getBytes()), JavaType.valueOf(Form.class))
114+
Map<String, ?> form = codec.read(HTTPResponseBody.some(value.getBytes()), JavaType.valueOf(Form.class))
115115
.map(CompletableFuture::join)
116116
.orElse(Collections.emptyMap());
117117

http-client-ktor/README.md

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
## http-client-ktor
2+
3+
This module provides to use [Ktor Client](https://ktor.io/docs/getting-started-ktor-client.html) as non-blocking, coroutine-based HTTP client implementation.
4+
5+
## Install
6+
7+
### Maven
8+
```xml
9+
<dependency>
10+
<groupId>com.github.ljtfreitas.julian-http-client</groupId>
11+
<artifactId>julian-http-client-http-client-ktor</artifactId>
12+
<version>${julian-http-client-version}</version>
13+
</dependency>
14+
```
15+
16+
### Gradle
17+
```kotlin
18+
dependencies {
19+
implementation("com.github.ljtfreitas.julian-http-client:julian-http-client-ktor:$julianHttpClientVersion")
20+
}
21+
```
22+
23+
## Usage
24+
25+
We need to configure the `ProxyBuilder` to use the implementation provided for this module:
26+
27+
```kotlin
28+
interface MyApi {}
29+
30+
val ktorHttpClient = KtorHTTPClient()
31+
32+
val myApi = proxy<MyApi>("http://my.api.com") {
33+
http {
34+
client {
35+
with(ktorHttpClient)
36+
}
37+
}
38+
}
39+
```
40+
41+
In order to configure the client, we can pass an additional block to the constructor:
42+
43+
```kotlin
44+
val ktorHttpClient = KtorHTTPClient {
45+
followRedirects = true
46+
47+
//any other configuration here
48+
}
49+
```
50+
51+
Or install plugins:
52+
53+
```kotlin
54+
val ktorHttpClient = KtorHTTPClient {
55+
install(HttpTimeout) {
56+
requestTimeoutMillis = 2000
57+
}
58+
59+
//any configuration here
60+
}
61+
```
62+
63+
The engine used by default is [CIO](https://ktor.io/docs/http-client-engines.html#cio), a fully asynchronous coroutine-based engine, with default options. We can customize it, of course:
64+
65+
```kotlin
66+
import io.ktor.client.engine.cio.CIO
67+
68+
val ktorHttpClient = KtorHTTPClient(CIO) {
69+
engine {
70+
// specific CIO options; see https://ktor.io/docs/http-client-engines.html#cio
71+
72+
}
73+
}
74+
```
75+
76+
And we can change the engine, if we want. For instance, [Apache](https://ktor.io/docs/http-client-engines.html#apache) engine
77+
78+
```kotlin
79+
import io.ktor.client.engine.apache.*
80+
81+
val ktorHttpClient = KtorHTTPClient(Apache) {
82+
engine {
83+
// specific Apache engine options; see https://ktor.io/docs/http-client-engines.html#apache
84+
85+
}
86+
}
87+
```

http-client-reactor-netty/README.md

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
## http-client-reactor-netty
2+
3+
This module provides to use [Reactor Netty](https://projectreactor.io/docs/netty/release/reference/index.html) as reactive, non-blocking HTTP client implementation.
4+
5+
## Install
6+
7+
### Maven
8+
```xml
9+
<dependency>
10+
<groupId>com.github.ljtfreitas.julian-http-client</groupId>
11+
<artifactId>julian-http-client-http-client-reactor-netty</artifactId>
12+
<version>${julian-http-client-version}</version>
13+
</dependency>
14+
```
15+
16+
### Gradle
17+
```kotlin
18+
dependencies {
19+
implementation("com.github.ljtfreitas.julian-http-client:julian-http-client-reactor-netty:$julianHttpClientVersion")
20+
}
21+
```
22+
23+
## Usage
24+
25+
We need to configure the `ProxyBuilder` to use the implementation provided for this module:
26+
27+
```java
28+
import com.github.ljtfreitas.julian.http.client.reactor.ReactorNettyHTTPClient;
29+
30+
interface MyApi {}
31+
32+
ReactorNettyHTTPClient reactorNettyHTTPClient = new ReactorNettyHTTPClient();
33+
34+
MyApi myApi = new ProxyBuilder()
35+
.http()
36+
.client()
37+
.with(reactorNettyHTTPClient)
38+
.and()
39+
.build(MyApi.class, "http://my.api.com");
40+
```
41+
42+
`ReactorNettyHTTPClient` uses a default [HttpClient](https://projectreactor.io/docs/netty/release/api/reactor/netty/http/client/HttpClient.html), but we can customize it:
43+
44+
```java
45+
import com.github.ljtfreitas.julian.http.client.reactor.ReactorNettyHTTPClient;
46+
import reactor.netty.http.client.HttpClient;
47+
48+
interface MyApi {}
49+
50+
HttpClient httpClient = HttpClient
51+
.create()
52+
// other HttpClient options here...
53+
54+
ReactorNettyHTTPClient reactorNettyHTTPClient = new ReactorNettyHTTPClient(httpClient);
55+
56+
MyApi myApi = new ProxyBuilder()
57+
.http()
58+
.client()
59+
.with(reactorNettyHTTPClient)
60+
.and()
61+
.build(MyApi.class, "http://my.api.com");
62+
```

0 commit comments

Comments
 (0)