diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/pom.xml b/spring-cloud/spring-cloud-bootstrap/gateway/pom.xml
index 3d8c40afdd..84dc2a6ca9 100644
--- a/spring-cloud/spring-cloud-bootstrap/gateway/pom.xml
+++ b/spring-cloud/spring-cloud-bootstrap/gateway/pom.xml
@@ -44,6 +44,10 @@
org.springframework.cloud
spring-cloud-starter-zipkin
+
+ org.springframework.cloud
+ spring-cloud-starter-feign
+
diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java
index 16aae66cab..10ed66bfd4 100644
--- a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java
+++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java
@@ -1,5 +1,7 @@
package com.baeldung.spring.cloud.bootstrap.gateway;
+import com.baeldung.spring.cloud.bootstrap.gateway.client.book.BooksClient;
+import com.baeldung.spring.cloud.bootstrap.gateway.client.rating.RatingsClient;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.EurekaClient;
import org.springframework.beans.factory.annotation.Autowired;
@@ -8,6 +10,7 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.cloud.netflix.ribbon.RibbonClientSpecification;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@@ -16,6 +19,8 @@ import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter;
import org.springframework.cloud.sleuth.zipkin.ZipkinProperties;
import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter;
import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.FilterType;
import org.springframework.web.client.RestTemplate;
import zipkin.Span;
@@ -25,6 +30,7 @@ import java.util.List;
@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
+@EnableFeignClients
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/book/Book.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/book/Book.java
new file mode 100644
index 0000000000..d6a4d9269b
--- /dev/null
+++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/book/Book.java
@@ -0,0 +1,46 @@
+package com.baeldung.spring.cloud.bootstrap.gateway.client.book;
+
+import com.baeldung.spring.cloud.bootstrap.gateway.client.rating.Rating;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+import java.util.List;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class Book {
+ private Long id;
+ private String author;
+ private String title;
+ private List ratings;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public List getRatings() {
+ return ratings;
+ }
+
+ public void setRatings(List ratings) {
+ this.ratings = ratings;
+ }
+}
diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/book/BooksClient.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/book/BooksClient.java
new file mode 100644
index 0000000000..beba760f10
--- /dev/null
+++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/book/BooksClient.java
@@ -0,0 +1,10 @@
+package com.baeldung.spring.cloud.bootstrap.gateway.client.book;
+
+import org.springframework.cloud.netflix.feign.FeignClient;
+import org.springframework.web.bind.annotation.*;
+
+@FeignClient(value = "book-service")
+public interface BooksClient {
+ @RequestMapping(method = RequestMethod.GET, value="/books/{bookId}")
+ Book getBookById(@PathVariable("bookId") Long bookId);
+}
diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/rating/Rating.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/rating/Rating.java
new file mode 100644
index 0000000000..21f9db2d98
--- /dev/null
+++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/rating/Rating.java
@@ -0,0 +1,34 @@
+package com.baeldung.spring.cloud.bootstrap.gateway.client.rating;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class Rating {
+ private Long id;
+ private Long bookId;
+ private int stars;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Long getBookId() {
+ return bookId;
+ }
+
+ public void setBookId(Long bookId) {
+ this.bookId = bookId;
+ }
+
+ public int getStars() {
+ return stars;
+ }
+
+ public void setStars(int stars) {
+ this.stars = stars;
+ }
+}
diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/rating/RatingsClient.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/rating/RatingsClient.java
new file mode 100644
index 0000000000..e82202e5a7
--- /dev/null
+++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/client/rating/RatingsClient.java
@@ -0,0 +1,15 @@
+package com.baeldung.spring.cloud.bootstrap.gateway.client.rating;
+
+import org.springframework.cloud.netflix.feign.FeignClient;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.List;
+
+@FeignClient(value = "rating-service")
+public interface RatingsClient {
+ @RequestMapping(method = RequestMethod.GET, value="/ratings")
+ List getRatingsByBookId(@RequestParam("bookId") Long bookId, @RequestHeader("Cookie") String session);
+}
diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/controller/CombinedController.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/controller/CombinedController.java
new file mode 100644
index 0000000000..f04991f81d
--- /dev/null
+++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/controller/CombinedController.java
@@ -0,0 +1,32 @@
+package com.baeldung.spring.cloud.bootstrap.gateway.controller;
+
+import com.baeldung.spring.cloud.bootstrap.gateway.client.book.Book;
+import com.baeldung.spring.cloud.bootstrap.gateway.client.book.BooksClient;
+import com.baeldung.spring.cloud.bootstrap.gateway.client.rating.Rating;
+import com.baeldung.spring.cloud.bootstrap.gateway.client.rating.RatingsClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/combined")
+public class CombinedController {
+
+ private final BooksClient booksClient;
+ private final RatingsClient ratingsClient;
+
+ @Autowired
+ public CombinedController(BooksClient booksClient, RatingsClient ratingsClient) {
+ this.booksClient = booksClient;
+ this.ratingsClient = ratingsClient;
+ }
+
+ @GetMapping
+ public Book getCombinedResponse(@RequestParam Long bookId, @CookieValue("SESSION") String session){
+ Book book = booksClient.getBookById(bookId);
+ List ratings = ratingsClient.getRatingsByBookId(bookId, "SESSION="+session);
+ book.setRatings(ratings);
+ return book;
+ }
+}
diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/LiveTest.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/LiveTest.java
index 04ddc0ee7a..2bef67934b 100644
--- a/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/LiveTest.java
+++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/LiveTest.java
@@ -1,5 +1,7 @@
package com.baeldung.spring.cloud.bootstrap.gateway;
+import com.baeldung.spring.cloud.bootstrap.gateway.client.book.Book;
+import com.baeldung.spring.cloud.bootstrap.gateway.client.rating.Rating;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.restassured.RestAssured;
import io.restassured.authentication.FormAuthConfig;
@@ -80,7 +82,9 @@ public class LiveTest {
@Test
public void whenAddnewRating_thenSuccess() {
- final Rating rating = new Rating(1L, 4);
+ final Rating rating = new Rating();
+ rating.setBookId(1L);
+ rating.setStars(4);
// request the protected resource
final Response ratingResponse = RestAssured.given()
@@ -98,7 +102,9 @@ public class LiveTest {
@Test
public void whenAddnewBook_thenSuccess() {
- final Book book = new Book("Baeldung", "How to spring cloud");
+ final Book book = new Book();
+ book.setTitle("How to spring cloud");
+ book.setAuthor("Baeldung");
// request the protected resource
final Response bookResponse = RestAssured.given()
@@ -115,83 +121,17 @@ public class LiveTest {
}
- @JsonIgnoreProperties(ignoreUnknown = true)
- public static class Book {
-
- private Long id;
- private String author;
- private String title;
-
- public Book() {
- }
-
- public Book(String author, String title) {
- this.author = author;
- this.title = title;
- }
-
- public String getAuthor() {
- return author;
- }
-
- public void setAuthor(String author) {
- this.author = author;
- }
-
- public String getTitle() {
- return title;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- public Long getId() {
- return id;
- }
-
- public void setId(Long id) {
- this.id = id;
- }
+ @Test
+ public void accessCombinedEndpoint() {
+ final Response response = RestAssured.given()
+ .auth()
+ .form("user", "password", formConfig)
+ .get(ROOT_URI + "/combined?bookId=1");
+ Assert.assertEquals(HttpStatus.OK.value(), response.getStatusCode());
+ Assert.assertNotNull(response.getBody());
+ final Book result = response.as(Book.class);
+ Assert.assertEquals(new Long(1), result.getId());
+ Assert.assertNotNull(result.getRatings());
+ Assert.assertTrue(result.getRatings().size() > 0);
}
-
- @JsonIgnoreProperties(ignoreUnknown = true)
- public static class Rating {
- private Long id;
- private Long bookId;
- private int stars;
-
- public Rating() {
- }
-
- public Rating(Long bookId, int stars) {
- this.bookId = bookId;
- this.stars = stars;
- }
-
- public Long getId() {
- return id;
- }
-
- public void setId(Long id) {
- this.id = id;
- }
-
- public Long getBookId() {
- return bookId;
- }
-
- public void setBookId(Long bookId) {
- this.bookId = bookId;
- }
-
- public int getStars() {
- return stars;
- }
-
- public void setStars(int stars) {
- this.stars = stars;
- }
- }
-
}
\ No newline at end of file