Skip to content

Commit 0397344

Browse files
authored
Merge pull request #6 from sashirestela/developer
Release 0.5.0
2 parents bf20b6a + f769ee3 commit 0397344

File tree

23 files changed

+762
-20
lines changed

23 files changed

+762
-20
lines changed

README.md

Lines changed: 170 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,172 @@
1-
# CleverClient
1+
[![codecov](https://codecov.io/gh/sashirestela/cleverclient/graph/badge.svg?token=PEYAFW3EWD)](https://codecov.io/gh/sashirestela/cleverclient)
2+
![Maven Central](https://img.shields.io/maven-central/v/io.github.sashirestela/cleverclient)
3+
![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/sashirestela/cleverclient/maven.yml)
24

5+
# 💎 CleverClient
36
Java library that makes it easier to use the Java's HttpClient to perform http operations, using interfaces.
7+
8+
9+
## 💡 Description
10+
CleverClient is a Java 11+ library that makes it easy to use the standard [HttpClient](https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpClient.html) component to call http services by using annotated interfaces.
11+
12+
For example, if we want to call the API [JsonPlaceHolder](https://jsonplaceholder.typicode.com/) with the endpoint ```/posts```, we just have to create an entity ```Post```, an interface ```PostService``` with special annotatons, and call the API through ```CleverClient```:
13+
14+
```
15+
// Entity
16+
public class Post {
17+
private Integer id;
18+
private String title;
19+
private String body;
20+
private Integer userId;
21+
22+
// Constructors , getters, setters, etc.
23+
}
24+
25+
// Interface
26+
public interface PostService {
27+
28+
@GET("/posts")
29+
List<Post> readPosts(@Query("_page") Integer page, @Query("_limit") Integer limit);
30+
31+
@GET("/posts/{postId}")
32+
Post readPost(@Path("postId") Integer postId);
33+
34+
@POST("/posts")
35+
Post createPost(@Body Post post);
36+
37+
}
38+
39+
// Use CleverClient to call the API
40+
var cleverClient = CleverClient.builder()
41+
.urlBase("https://jsonplaceholder.typicode.com/")
42+
.build();
43+
44+
var postService = cleverClient.create(PostService.class);
45+
46+
var page = 1;
47+
var limit = 5;
48+
var postId = 17;
49+
var userId = 3;
50+
51+
// Example Read Posts
52+
var postsList = postService.readPosts(page, limit);
53+
postsList.forEach(System.out::println);
54+
55+
// Example Read Post
56+
var onePost = postService.readPost(postId);
57+
System.out.println(onePost);
58+
59+
// Example Create Post
60+
var newPost = postService.createPost(new Post(
61+
null,
62+
"Hello",
63+
"Hello word, you are very welcome!",
64+
userId));
65+
System.out.println(newPost);
66+
```
67+
68+
69+
## 🛠️ Installation
70+
You can install CleverClient by adding the following dependency to your Maven project:
71+
72+
```xml
73+
<dependency>
74+
<groupId>io.github.sashirestela</groupId>
75+
<artifactId>cleverclient</artifactId>
76+
<version>[latest version]</version>
77+
</dependency>
78+
```
79+
80+
Or alternatively using Gradle:
81+
82+
```groovy
83+
dependencies {
84+
implementation 'io.github.sashirestela:cleverclient:[latest version]'
85+
}
86+
```
87+
88+
Take in account that you need to use **Java 11 or above**.
89+
90+
91+
## 📕 Features
92+
93+
### CleverClient Builder
94+
We have the following attributes to create a CleverClient object:
95+
96+
| Attribute | Description | Required |
97+
| ----------- |------------------------------------|-----------|
98+
| urlBase | Api's url | mandatory |
99+
| headers | Pairs of headers name/value | optional |
100+
| httpClient | Java HttpClient object | optional |
101+
| endOfStream | Text used to mark final of streams | optional |
102+
103+
Example:
104+
105+
```
106+
final var URL_BASE = "https://api.example.com";
107+
final var AUTHORIZATION_HEADER = "Authorization";
108+
final var BEARER_AUTHORIZATION = "Bearer qwertyasdfghzxcvb";
109+
final var END_OF_STREAM = "[DONE]";
110+
111+
var httpClient = HttpClient.newBuilder()
112+
.version(Version.HTTP_1_1)
113+
.followRedirects(Redirect.NORMAL)
114+
.connectTimeout(Duration.ofSeconds(20))
115+
.executor(Executors.newFixedThreadPool(3))
116+
.proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80)))
117+
.build();
118+
119+
var cleverClient = CleverClient.builder()
120+
.urlBase(URL_BASE)
121+
.headers(Arrays.asList(AUTHORIZATION_HEADER, BEARER_AUTHORIZATION))
122+
.httpClient(httpClient)
123+
.endOfStream(END_OF_STREAM)
124+
.build();
125+
```
126+
127+
### Interface Annotations
128+
129+
| Annotation | Target | Value |
130+
|------------|-----------|--------------------------|
131+
| Resource | Interface | Resource's url |
132+
| GET | Method | GET endpoint's url |
133+
| POST | Method | POST endpoint's url |
134+
| PUT | Method | PUT endpoint's url |
135+
| DELETE | Method | DELETE endpoint's url |
136+
| Multipart | Method | None. Mark for multipart |
137+
| Path | Parameter | Path parameter name |
138+
| Query | Parameter | Query parameter name |
139+
140+
141+
## ✳ Examples
142+
Some examples have been created in the folder [example](https://github.com/sashirestela/cleverclient/tree/main/src/example/java/io/github/sashirestela/cleverclient/example) and you can follow the next steps to execute them:
143+
* Clone this respository:
144+
```
145+
git clone https://github.com/sashirestela/cleverclient.git
146+
cd cleverclient
147+
```
148+
* Build the project:
149+
```
150+
mvn clean install
151+
```
152+
* Run example:
153+
```
154+
mvn exec:java -Dexec.mainClass=io.github.sashirestela.cleverclient.example.<className> [logOptions]
155+
```
156+
Where:
157+
158+
* ```<className>``` is mandatory and must be one of the values:
159+
* BasicExample
160+
* StreamExample (This requires you have an OpenAI account and set the env variable OPENAI_API_TOKEN)
161+
162+
* ```[logOptions]``` are optional and you can you use them to set:
163+
* Logger lever: ```-Dorg.slf4j.simpleLogger.defaultLogLevel=<logLevel>```
164+
* Logger file: ```-Dorg.slf4j.simpleLogger.logFile=<logFile>```
165+
* For example, to run the BasicExample with all the log options:
166+
* ```mvn exec:java -Dexec.mainClass=io.github.sashirestela.cleverclient.example.BasicExample -Dorg.slf4j.simpleLogger.defaultLogLevel=debug -Dorg.slf4j.simpleLogger.logFile=example.log```
167+
168+
169+
## 📄 License
170+
CleverClient is licensed under the MIT License. See the
171+
[LICENSE](https://github.com/sashirestela/cleverclient/blob/main/LICENSE) file
172+
for more information.

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>io.github.sashirestela</groupId>
88
<artifactId>cleverclient</artifactId>
9-
<version>0.4.1</version>
9+
<version>0.5.0</version>
1010
<packaging>jar</packaging>
1111

1212
<name>cleverclient</name>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package io.github.sashirestela.cleverclient.example;
2+
3+
import io.github.sashirestela.cleverclient.CleverClient;
4+
import io.github.sashirestela.cleverclient.example.jsonplaceholder.Post;
5+
import io.github.sashirestela.cleverclient.example.jsonplaceholder.PostService;
6+
7+
public class BasicExample {
8+
9+
public static void main(String[] args) {
10+
final var URL_BASE = "https://jsonplaceholder.typicode.com";
11+
12+
var cleverClient = CleverClient.builder()
13+
.urlBase(URL_BASE)
14+
.build();
15+
var postService = cleverClient.create(PostService.class);
16+
17+
var page = 1;
18+
var limit = 5;
19+
var postId = 17;
20+
var userId = 3;
21+
22+
showTitle("Example Read Posts");
23+
var postsList = postService.readPosts(page, limit);
24+
postsList.forEach(System.out::println);
25+
26+
showTitle("Example Read Post");
27+
var onePost = postService.readPost(postId);
28+
System.out.println(onePost);
29+
30+
showTitle("Example Create Post");
31+
var newPost = postService.createPost(Post.builder()
32+
.title("Hello")
33+
.body("Hello word, you are very welcome!")
34+
.userId(userId)
35+
.build());
36+
System.out.println(newPost);
37+
38+
showTitle("Example Update Post");
39+
var editPost = postService.updatePost(postId, Post.builder()
40+
.title("Hello")
41+
.body("Hello word, you are very welcome!")
42+
.userId(userId)
43+
.build());
44+
System.out.println(editPost);
45+
46+
showTitle("Example Delete Post");
47+
postService.deletePost(postId);
48+
System.out.println("Post was deleted");
49+
}
50+
51+
private static void showTitle(String title) {
52+
final var times = 50;
53+
System.out.println("=".repeat(times));
54+
System.out.println(title);
55+
System.out.println("-".repeat(times));
56+
}
57+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package io.github.sashirestela.cleverclient.example;
2+
3+
import java.util.Arrays;
4+
5+
import io.github.sashirestela.cleverclient.CleverClient;
6+
import io.github.sashirestela.cleverclient.example.openai.ChatRequest;
7+
import io.github.sashirestela.cleverclient.example.openai.ChatResponse;
8+
import io.github.sashirestela.cleverclient.example.openai.ChatService;
9+
import io.github.sashirestela.cleverclient.example.openai.Message;
10+
11+
/**
12+
* Before running this example you must have an OpenAI account and keep your Api
13+
* Key in an environment variable called OPENAI_API_KEY.
14+
*
15+
* @see https://platform.openai.com/docs/api-reference/authentication
16+
*/
17+
public class StreamExample {
18+
19+
public static void main(String[] args) {
20+
final var URL_BASE = "https://api.openai.com";
21+
final var AUTHORIZATION_HEADER = "Authorization";
22+
final var BEARER_AUTHORIZATION = "Bearer " + System.getenv("OPENAI_API_KEY");
23+
final var END_OF_STREAM = "[DONE]";
24+
25+
var cleverClient = CleverClient.builder()
26+
.urlBase(URL_BASE)
27+
.headers(Arrays.asList(AUTHORIZATION_HEADER, BEARER_AUTHORIZATION))
28+
.endOfStream(END_OF_STREAM)
29+
.build();
30+
var chatService = cleverClient.create(ChatService.class);
31+
32+
var chatRequest = ChatRequest.builder()
33+
.model("gpt-3.5-turbo")
34+
.messages(Arrays.asList(
35+
new Message("user", "Write an article about AI, no more than 100 words.")))
36+
.temperature(0.7)
37+
.stream(true)
38+
.build();
39+
40+
showTitle("Example Create Synchronous Stream");
41+
var chatResponseSync = chatService.createSyncStream(chatRequest);
42+
chatResponseSync
43+
.filter(chatResp -> chatResp.firstContent() != null)
44+
.map(ChatResponse::firstContent)
45+
.forEach(System.out::print);
46+
System.out.println();
47+
48+
showTitle("Example Create Asynchronous Stream");
49+
var chatResponseAsync = chatService.createAsyncStream(chatRequest).join();
50+
chatResponseAsync
51+
.filter(chatResp -> chatResp.firstContent() != null)
52+
.map(ChatResponse::firstContent)
53+
.forEach(System.out::print);
54+
System.out.println();
55+
}
56+
57+
private static void showTitle(String title) {
58+
final var times = 50;
59+
System.out.println("=".repeat(times));
60+
System.out.println(title);
61+
System.out.println("-".repeat(times));
62+
}
63+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package io.github.sashirestela.cleverclient.example.jsonplaceholder;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Builder;
5+
import lombok.Data;
6+
import lombok.NoArgsConstructor;
7+
8+
@NoArgsConstructor
9+
@AllArgsConstructor
10+
@Builder
11+
@Data
12+
public class Post {
13+
private Integer id;
14+
private String title;
15+
private String body;
16+
private Integer userId;
17+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package io.github.sashirestela.cleverclient.example.jsonplaceholder;
2+
3+
import java.util.List;
4+
5+
import io.github.sashirestela.cleverclient.annotation.Body;
6+
import io.github.sashirestela.cleverclient.annotation.DELETE;
7+
import io.github.sashirestela.cleverclient.annotation.GET;
8+
import io.github.sashirestela.cleverclient.annotation.POST;
9+
import io.github.sashirestela.cleverclient.annotation.PUT;
10+
import io.github.sashirestela.cleverclient.annotation.Path;
11+
import io.github.sashirestela.cleverclient.annotation.Query;
12+
13+
public interface PostService {
14+
15+
@GET("/posts")
16+
List<Post> readPosts(@Query("_page") Integer page, @Query("_limit") Integer limit);
17+
18+
@GET("/posts/{postId}")
19+
Post readPost(@Path("postId") Integer postId);
20+
21+
@POST("/posts")
22+
Post createPost(@Body Post post);
23+
24+
@PUT("/posts/{postId}")
25+
Post updatePost(@Path("postId") Integer postId, @Body Post post);
26+
27+
@DELETE("/posts/{postId}")
28+
Post deletePost(@Path("postId") Integer postId);
29+
30+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package io.github.sashirestela.cleverclient.example.openai;
2+
3+
import java.util.List;
4+
5+
import lombok.AllArgsConstructor;
6+
import lombok.Builder;
7+
import lombok.Getter;
8+
9+
@AllArgsConstructor
10+
@Getter
11+
@Builder
12+
public class ChatRequest {
13+
private String model;
14+
private List<Message> messages;
15+
private Double temperature;
16+
private Boolean stream;
17+
}

0 commit comments

Comments
 (0)