diff --git a/httpClients/boot-restclient/pom.xml b/httpClients/boot-restclient/pom.xml
index 0bc42615a..f6bbc2498 100644
--- a/httpClients/boot-restclient/pom.xml
+++ b/httpClients/boot-restclient/pom.xml
@@ -33,6 +33,14 @@
org.springframework.boot
spring-boot-starter-validation
+
+ org.springframework.retry
+ spring-retry
+
+
+ org.springframework
+ spring-aspects
+
org.springdoc
springdoc-openapi-starter-webmvc-ui
diff --git a/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/RestClientConfiguration.java b/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/RestClientConfiguration.java
index 5cf8c540b..1b3869c67 100644
--- a/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/RestClientConfiguration.java
+++ b/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/config/RestClientConfiguration.java
@@ -16,12 +16,14 @@
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.JdkClientHttpRequestFactory;
import org.springframework.lang.NonNull;
+import org.springframework.retry.annotation.EnableRetry;
import org.springframework.util.StreamUtils;
import org.springframework.web.client.RestClient;
import org.springframework.web.util.DefaultUriBuilderFactory;
@Configuration(proxyBeanMethods = false)
@Slf4j
+@EnableRetry
public class RestClientConfiguration {
@Bean
@@ -90,7 +92,10 @@ HttpClient jdkClient() {
@Bean
JdkClientHttpRequestFactory jdkClientHttpRequestFactory(@NonNull HttpClient jdkClient) {
- return new JdkClientHttpRequestFactory(jdkClient);
+ JdkClientHttpRequestFactory jdkClientHttpRequestFactory =
+ new JdkClientHttpRequestFactory(jdkClient);
+ jdkClientHttpRequestFactory.setReadTimeout(Duration.ofSeconds(60));
+ return jdkClientHttpRequestFactory;
}
// BufferingClientHttpRequestFactory allows us to read the response body multiple times for a
diff --git a/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/exception/MyCustomRuntimeException.java b/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/exception/MyCustomClientException.java
similarity index 69%
rename from httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/exception/MyCustomRuntimeException.java
rename to httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/exception/MyCustomClientException.java
index 4bf905f4c..6b42a9d30 100644
--- a/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/exception/MyCustomRuntimeException.java
+++ b/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/exception/MyCustomClientException.java
@@ -5,11 +5,11 @@
import org.springframework.http.HttpStatusCode;
@Getter
-public class MyCustomRuntimeException extends RuntimeException {
+public class MyCustomClientException extends RuntimeException {
private final HttpStatusCode statusCode;
private final HttpHeaders headers;
- public MyCustomRuntimeException(HttpStatusCode statusCode, HttpHeaders headers) {
+ public MyCustomClientException(HttpStatusCode statusCode, HttpHeaders headers) {
this.statusCode = statusCode;
this.headers = headers;
}
diff --git a/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/services/HttpClientService.java b/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/services/HttpClientService.java
new file mode 100644
index 000000000..31668c567
--- /dev/null
+++ b/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/services/HttpClientService.java
@@ -0,0 +1,86 @@
+package com.example.restclient.bootrestclient.services;
+
+import com.example.restclient.bootrestclient.exception.MyCustomClientException;
+import java.net.URI;
+import java.util.Map;
+import java.util.function.Function;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.lang.Nullable;
+import org.springframework.retry.annotation.Backoff;
+import org.springframework.retry.annotation.Retryable;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.client.HttpServerErrorException;
+import org.springframework.web.client.RestClient;
+import org.springframework.web.util.UriBuilder;
+
+@Service
+@Retryable(
+ retryFor = {HttpServerErrorException.class},
+ maxAttempts = 2,
+ backoff = @Backoff(delay = 5000))
+public class HttpClientService {
+
+ private final RestClient restClient;
+
+ public HttpClientService(RestClient restClient) {
+ this.restClient = restClient;
+ }
+
+ T callAndFetchResponse(
+ Function uriFunction,
+ HttpMethod httpMethod,
+ @Nullable Object body,
+ Class bodyType) {
+ return callServer(uriFunction, httpMethod, null, body, bodyType, null);
+ }
+
+ T callAndFetchResponse(
+ Function uriFunction,
+ HttpMethod httpMethod,
+ @Nullable Map headers,
+ Class bodyType) {
+ return callServer(uriFunction, httpMethod, headers, null, bodyType, null);
+ }
+
+ T callAndFetchResponse(
+ Function uriFunction,
+ HttpMethod httpMethod,
+ @Nullable Object body,
+ ParameterizedTypeReference bodyType) {
+ return callServer(uriFunction, httpMethod, null, body, null, bodyType);
+ }
+
+ private T callServer(
+ Function uriFunction,
+ HttpMethod httpMethod,
+ Map headers,
+ Object body,
+ Class bodyType,
+ ParameterizedTypeReference typeReferenceBodyType) {
+ RestClient.RequestBodySpec uri = restClient.method(httpMethod).uri(uriFunction);
+ if (!CollectionUtils.isEmpty(headers)) {
+ uri.headers(
+ httpHeader ->
+ headers.keySet().forEach(key -> httpHeader.add(key, headers.get(key))));
+ }
+ if (body != null) {
+ uri.body(body);
+ }
+ RestClient.ResponseSpec responseSpec =
+ uri.retrieve()
+ .onStatus(
+ HttpStatusCode::is4xxClientError,
+ (request, response) -> {
+ throw new MyCustomClientException(
+ response.getStatusCode(), response.getHeaders());
+ });
+ if (bodyType != null) {
+ return responseSpec.body(bodyType);
+ } else {
+ return responseSpec.body(typeReferenceBodyType);
+ }
+ }
+}
diff --git a/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/services/PostService.java b/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/services/PostService.java
index 77c0238ed..069e645e1 100644
--- a/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/services/PostService.java
+++ b/httpClients/boot-restclient/src/main/java/com/example/restclient/bootrestclient/services/PostService.java
@@ -1,81 +1,63 @@
package com.example.restclient.bootrestclient.services;
-import com.example.restclient.bootrestclient.exception.MyCustomRuntimeException;
import com.example.restclient.bootrestclient.model.response.PostDto;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import org.springframework.core.ParameterizedTypeReference;
-import org.springframework.http.HttpStatusCode;
-import org.springframework.http.MediaType;
+import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
-import org.springframework.web.client.RestClient;
@Service
public class PostService {
- private final RestClient restClient;
+ private final HttpClientService httpClientService;
- public PostService(RestClient restClient) {
- this.restClient = restClient;
+ public PostService(HttpClientService httpClientService) {
+ this.httpClientService = httpClientService;
}
public List findAllPosts() {
- return restClient
- .get()
- .uri("/posts")
- .accept(MediaType.APPLICATION_JSON)
- .retrieve()
- .body(new ParameterizedTypeReference>() {});
+ return httpClientService.callAndFetchResponse(
+ uriBuilder -> uriBuilder.path("/posts").build(),
+ HttpMethod.GET,
+ null,
+ new ParameterizedTypeReference>() {});
}
public Optional findPostById(Long id) {
- return Optional.ofNullable(
- restClient
- .get()
- .uri(uriBuilder -> uriBuilder.path("/posts/{postId}").build(id))
- .accept(MediaType.APPLICATION_JSON)
- .retrieve()
- .onStatus(
- HttpStatusCode::is4xxClientError,
- (request, response) -> {
- throw new MyCustomRuntimeException(
- response.getStatusCode(), response.getHeaders());
- })
- .body(PostDto.class));
+ PostDto response =
+ httpClientService.callAndFetchResponse(
+ uriBuilder -> uriBuilder.path("/posts/{postId}").build(id),
+ HttpMethod.GET,
+ Map.of("apiKey", "123456"),
+ PostDto.class);
+ return Optional.ofNullable(response);
}
public PostDto savePost(PostDto post) {
- return restClient
- .post()
- .uri("/posts")
- .contentType(MediaType.APPLICATION_JSON)
- .body(post)
- .retrieve()
- .body(PostDto.class);
+ return httpClientService.callAndFetchResponse(
+ uriBuilder -> uriBuilder.path("/posts").build(),
+ HttpMethod.POST,
+ post,
+ PostDto.class);
}
public Optional updatePostById(Long id, PostDto postDto) {
- return Optional.ofNullable(
- restClient
- .put()
- .uri(uriBuilder -> uriBuilder.path("/posts/{postId}").build(id))
- .contentType(MediaType.APPLICATION_JSON)
- .body(postDto)
- .retrieve()
- .onStatus(
- HttpStatusCode::is4xxClientError,
- (request, response) -> {
- throw new MyCustomRuntimeException(
- response.getStatusCode(), response.getHeaders());
- })
- .body(PostDto.class));
+ PostDto response =
+ httpClientService.callAndFetchResponse(
+ uriBuilder -> uriBuilder.path("/posts/{postId}").build(id),
+ HttpMethod.PUT,
+ postDto,
+ PostDto.class);
+ return Optional.ofNullable(response);
}
public String deletePostById(Long id) {
- return restClient
- .delete()
- .uri(uriBuilder -> uriBuilder.path("/posts/{postId}").build(id))
- .retrieve()
- .body(String.class);
+ return httpClientService.callAndFetchResponse(
+ uriBuilder -> uriBuilder.path("/posts/{postId}").build(id),
+ HttpMethod.DELETE,
+ null,
+ String.class);
}
}