1 package fr.tiogars.chat.client;
2
3 import com.fasterxml.jackson.core.type.TypeReference;
4 import com.fasterxml.jackson.databind.ObjectMapper;
5 import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
6
7 import java.io.IOException;
8 import java.net.URI;
9 import java.net.http.HttpClient;
10 import java.net.http.HttpRequest;
11 import java.net.http.HttpResponse;
12 import java.util.List;
13
14
15
16
17
18
19 public class TaskClient {
20
21 private static final String API_PATH = "/api/v1/chat";
22 private static final String APPLICATION_JSON = "application/json";
23 private static final String TEXT_CSV = "text/csv";
24 private static final TypeReference<List<Task>> TEMPLATE_LIST = new TypeReference<>() {
25 };
26
27 private final URI baseUri;
28 private final HttpClient httpClient;
29 private final ObjectMapper objectMapper;
30
31
32
33
34
35
36 public TaskClient(URI baseUri) {
37 this(baseUri, HttpClient.newHttpClient(), new ObjectMapper().registerModule(new JavaTimeModule())
38 .disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS));
39 }
40
41 TaskClient(URI baseUri, HttpClient httpClient, ObjectMapper objectMapper) {
42 this.baseUri = baseUri;
43 this.httpClient = httpClient;
44 this.objectMapper = objectMapper;
45 }
46
47
48
49
50
51
52
53
54
55
56 public Task create(CreateTaskRequest request) throws IOException, InterruptedException {
57 return sendJson(jsonRequest(uri(""), "POST", request), Task.class, 201);
58 }
59
60
61
62
63
64
65
66
67
68 public List<Task> findAll() throws IOException, InterruptedException {
69 return sendJson(getRequest(uri(""), APPLICATION_JSON), TEMPLATE_LIST, 200);
70 }
71
72
73
74
75
76
77
78
79
80
81 public Task findById(long id) throws IOException, InterruptedException {
82 return sendJson(getRequest(uri("/" + id), APPLICATION_JSON), Task.class, 200);
83 }
84
85
86
87
88
89
90
91
92
93
94
95 public Task update(long id, UpdateTaskRequest request) throws IOException, InterruptedException {
96 return sendJson(jsonRequest(uri("/" + id), "PUT", request), Task.class, 200);
97 }
98
99
100
101
102
103
104
105
106
107 public void delete(long id) throws IOException, InterruptedException {
108 HttpRequest request = HttpRequest.newBuilder(uri("/" + id)).DELETE().build();
109 send(request, 204);
110 }
111
112
113
114
115
116
117
118
119
120
121 public List<Task> seed(List<CreateTaskRequest> requests) throws IOException, InterruptedException {
122 return sendJson(jsonRequest(uri("/seed"), "POST", requests), TEMPLATE_LIST, 201);
123 }
124
125
126
127
128
129
130
131
132
133
134 public List<Task> importJson(List<CreateTaskRequest> requests)
135 throws IOException, InterruptedException {
136 return sendJson(jsonRequest(uri("/import.json"), "POST", requests), TEMPLATE_LIST, 201);
137 }
138
139
140
141
142
143
144
145
146
147
148 public List<Task> importCsv(String csv) throws IOException, InterruptedException {
149 HttpRequest request = HttpRequest.newBuilder(uri("/import.csv"))
150 .header("Content-Type", TEXT_CSV)
151 .header("Accept", APPLICATION_JSON)
152 .POST(HttpRequest.BodyPublishers.ofString(csv))
153 .build();
154 return sendJson(request, TEMPLATE_LIST, 201);
155 }
156
157
158
159
160
161
162
163
164
165 public List<Task> exportJson() throws IOException, InterruptedException {
166 return sendJson(getRequest(uri("/export.json"), APPLICATION_JSON), TEMPLATE_LIST, 200);
167 }
168
169
170
171
172
173
174
175
176
177 public String exportCsv() throws IOException, InterruptedException {
178 return send(getRequest(uri("/export.csv"), TEXT_CSV), 200).body();
179 }
180
181 private HttpRequest jsonRequest(URI uri, String method, Object body) throws IOException {
182 return HttpRequest.newBuilder(uri)
183 .header("Content-Type", APPLICATION_JSON)
184 .header("Accept", APPLICATION_JSON)
185 .method(method, HttpRequest.BodyPublishers.ofString(objectMapper.writeValueAsString(body)))
186 .build();
187 }
188
189 private HttpRequest getRequest(URI uri, String accept) {
190 return HttpRequest.newBuilder(uri).header("Accept", accept).GET().build();
191 }
192
193 private <T> T sendJson(HttpRequest request, Class<T> responseType, int expectedStatus)
194 throws IOException, InterruptedException {
195 return objectMapper.readValue(send(request, expectedStatus).body(), responseType);
196 }
197
198 private <T> T sendJson(HttpRequest request, TypeReference<T> responseType, int expectedStatus)
199 throws IOException, InterruptedException {
200 return objectMapper.readValue(send(request, expectedStatus).body(), responseType);
201 }
202
203 private HttpResponse<String> send(HttpRequest request, int expectedStatus) throws IOException, InterruptedException {
204 HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
205 if (response.statusCode() != expectedStatus) {
206 throw new TaskException(
207 "Expected HTTP " + expectedStatus + " but received " + response.statusCode());
208 }
209 return response;
210 }
211
212 private URI uri(String suffix) {
213 return baseUri.resolve(API_PATH + suffix);
214 }
215 }