diff --git a/patterns-modules/design-patterns-architectural/pom.xml b/patterns-modules/design-patterns-architectural/pom.xml
index f18976747743..eb61a36c9abf 100644
--- a/patterns-modules/design-patterns-architectural/pom.xml
+++ b/patterns-modules/design-patterns-architectural/pom.xml
@@ -72,8 +72,6 @@
5.5.14
3.20.4
3.14.0
- 1.7.32
- 1.2.7
\ No newline at end of file
diff --git a/patterns-modules/design-patterns-architectural/src/main/java/com/baeldung/ambassadorpattern/AmbassadorPatternApplication.java b/patterns-modules/design-patterns-architectural/src/main/java/com/baeldung/ambassadorpattern/AmbassadorPatternApplication.java
new file mode 100644
index 000000000000..4bf29907d2e7
--- /dev/null
+++ b/patterns-modules/design-patterns-architectural/src/main/java/com/baeldung/ambassadorpattern/AmbassadorPatternApplication.java
@@ -0,0 +1,16 @@
+package com.baeldung.ambassadorpattern;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.retry.annotation.EnableRetry;
+
+@EnableRetry
+@EnableCaching
+@SpringBootApplication
+public class AmbassadorPatternApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(AmbassadorPatternApplication.class, args);
+ }
+}
\ No newline at end of file
diff --git a/patterns-modules/design-patterns-architectural/src/main/java/com/baeldung/ambassadorpattern/HttpAmbassadorController.java b/patterns-modules/design-patterns-architectural/src/main/java/com/baeldung/ambassadorpattern/HttpAmbassadorController.java
new file mode 100644
index 000000000000..1c2b349764b8
--- /dev/null
+++ b/patterns-modules/design-patterns-architectural/src/main/java/com/baeldung/ambassadorpattern/HttpAmbassadorController.java
@@ -0,0 +1,21 @@
+package com.baeldung.ambassadorpattern;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/v1/http-ambassador/names")
+public class HttpAmbassadorController {
+
+ private final HttpAmbassadorNamesApiClient httpAmbassadorNamesApiClient;
+
+ public HttpAmbassadorController(HttpAmbassadorNamesApiClient httpAmbassadorNamesApiClient) {
+ this.httpAmbassadorNamesApiClient = httpAmbassadorNamesApiClient;
+ }
+
+ @GetMapping
+ public String get() {
+ return httpAmbassadorNamesApiClient.getResponse();
+ }
+}
diff --git a/patterns-modules/design-patterns-architectural/src/main/java/com/baeldung/ambassadorpattern/HttpAmbassadorNamesApiClient.java b/patterns-modules/design-patterns-architectural/src/main/java/com/baeldung/ambassadorpattern/HttpAmbassadorNamesApiClient.java
new file mode 100644
index 000000000000..4b33e1297c3c
--- /dev/null
+++ b/patterns-modules/design-patterns-architectural/src/main/java/com/baeldung/ambassadorpattern/HttpAmbassadorNamesApiClient.java
@@ -0,0 +1,46 @@
+package com.baeldung.ambassadorpattern;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.retry.annotation.Backoff;
+import org.springframework.retry.annotation.Recover;
+import org.springframework.retry.annotation.Retryable;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.HttpServerErrorException;
+import org.springframework.web.client.RestTemplate;
+
+@Component
+public class HttpAmbassadorNamesApiClient {
+
+ private final RestTemplate restTemplate;
+ private final Logger logger = LoggerFactory.getLogger(HttpAmbassadorNamesApiClient.class);
+ public final String apiUrl;
+
+ public HttpAmbassadorNamesApiClient(RestTemplate restTemplate, @Value("${names-api-url}") String apiUrl) {
+ this.restTemplate = restTemplate;
+ this.apiUrl = apiUrl;
+ }
+
+ @Cacheable(value = "httpResponses", key = "#root.target.apiUrl", unless = "#result == null")
+ @Retryable(value = { HttpServerErrorException.class }, maxAttempts = 5, backoff = @Backoff(delay = 1000))
+ public String getResponse() {
+ try {
+ String result = restTemplate.getForObject(apiUrl, String.class);
+ logger.info("HTTP call completed successfully to url={}", apiUrl);
+ return result;
+ } catch (HttpClientErrorException e) {
+ logger.error("HTTP Client Error error_code={} message={}", e.getStatusCode(), e.getMessage());
+ throw e;
+ }
+ }
+
+ @Recover
+ public String recover(Exception e) {
+ final String defaultResponse = "default";
+ logger.error("Too many retry attempts. Falling back to default. error={} default={}", e.getMessage(), defaultResponse);
+ return defaultResponse;
+ }
+}
diff --git a/patterns-modules/design-patterns-architectural/src/main/java/com/baeldung/ambassadorpattern/RestTemplateConfig.java b/patterns-modules/design-patterns-architectural/src/main/java/com/baeldung/ambassadorpattern/RestTemplateConfig.java
new file mode 100644
index 000000000000..cd84fb9c7e00
--- /dev/null
+++ b/patterns-modules/design-patterns-architectural/src/main/java/com/baeldung/ambassadorpattern/RestTemplateConfig.java
@@ -0,0 +1,31 @@
+package com.baeldung.ambassadorpattern;
+
+import java.time.Duration;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+@Configuration
+public class RestTemplateConfig {
+
+ private final int connectTimeoutSeconds;
+ private final int readTimeoutSeconds;
+ private final RestTemplateBuilder restTemplateBuilder;
+
+ public RestTemplateConfig(RestTemplateBuilder restTemplateBuilder, @Value("${http.client.read-timeout-seconds}") int readTimeoutSeconds,
+ @Value("${http.client.connect-timeout-seconds}") int connectTimeoutSeconds) {
+ this.restTemplateBuilder = restTemplateBuilder;
+ this.readTimeoutSeconds = readTimeoutSeconds;
+ this.connectTimeoutSeconds = connectTimeoutSeconds;
+ }
+
+ @Bean
+ public RestTemplate restTemplate() {
+ return restTemplateBuilder.setConnectTimeout(Duration.ofMillis(connectTimeoutSeconds))
+ .setReadTimeout(Duration.ofMillis(readTimeoutSeconds))
+ .build();
+ }
+}
diff --git a/patterns-modules/design-patterns-architectural/src/main/resources/application.properties b/patterns-modules/design-patterns-architectural/src/main/resources/application.properties
new file mode 100644
index 000000000000..a38f6d9937bd
--- /dev/null
+++ b/patterns-modules/design-patterns-architectural/src/main/resources/application.properties
@@ -0,0 +1,3 @@
+http.client.connect-timeout-seconds=2000
+http.client.read-timeout-seconds=3000
+names-api-url=https://domain.com/names/api
\ No newline at end of file
diff --git a/patterns-modules/design-patterns-architectural/src/test/java/com/baeldung/ambassadorpattern/HttpAmbassadorControllerIntegrationTest.java b/patterns-modules/design-patterns-architectural/src/test/java/com/baeldung/ambassadorpattern/HttpAmbassadorControllerIntegrationTest.java
new file mode 100644
index 000000000000..394e5f1ec6d8
--- /dev/null
+++ b/patterns-modules/design-patterns-architectural/src/test/java/com/baeldung/ambassadorpattern/HttpAmbassadorControllerIntegrationTest.java
@@ -0,0 +1,38 @@
+package com.baeldung.ambassadorpattern;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.web.client.RestTemplate;
+
+@WebMvcTest(HttpAmbassadorController.class)
+@Import({ HttpAmbassadorNamesApiClient.class, TestConfig.class })
+@AutoConfigureMockMvc(addFilters = false)
+class HttpAmbassadorControllerIntegrationTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @MockBean
+ private RestTemplate restTemplate;
+
+ @Test
+ void givenExternalCallMock_whenGetNames_thenReturnExpectedName() throws Exception {
+ String expectedResponse = "{'name': 'Baeldung'}";
+ when(restTemplate.getForObject(eq("https://domain.com/names/api"), eq(String.class))).thenReturn(expectedResponse);
+
+ mockMvc.perform(get("/v1/http-ambassador/names"))
+ .andExpect(status().isOk())
+ .andExpect(content().string(expectedResponse));
+ }
+}
\ No newline at end of file
diff --git a/patterns-modules/design-patterns-architectural/src/test/java/com/baeldung/ambassadorpattern/TestConfig.java b/patterns-modules/design-patterns-architectural/src/test/java/com/baeldung/ambassadorpattern/TestConfig.java
new file mode 100644
index 000000000000..927035c8d1c5
--- /dev/null
+++ b/patterns-modules/design-patterns-architectural/src/test/java/com/baeldung/ambassadorpattern/TestConfig.java
@@ -0,0 +1,11 @@
+package com.baeldung.ambassadorpattern;
+
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.retry.annotation.EnableRetry;
+
+@Configuration
+@EnableRetry
+public class TestConfig {
+
+}