Skip to content

Commit 665256e

Browse files
iluwatar#297 Create Spring Boot-backed API Gateway that aggregates calls to the Image and Price microservices
1 parent 01737bc commit 665256e

File tree

14 files changed

+208
-73
lines changed

14 files changed

+208
-73
lines changed

api-gateway/pom.xml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,66 @@
99
</parent>
1010
<modelVersion>4.0.0</modelVersion>
1111
<artifactId>api-gateway</artifactId>
12+
<packaging>jar</packaging>
13+
14+
<properties>
15+
<spring.version>4.2.5.RELEASE</spring.version>
16+
<spring-boot.version>1.3.3.RELEASE</spring-boot.version>
17+
</properties>
18+
19+
<dependencyManagement>
20+
<dependencies>
21+
<dependency>
22+
<groupId>org.springframework.boot</groupId>
23+
<artifactId>spring-boot-dependencies</artifactId>
24+
<version>${spring-boot.version}</version>
25+
<type>pom</type>
26+
<scope>import</scope>
27+
</dependency>
28+
</dependencies>
29+
</dependencyManagement>
1230
<dependencies>
31+
<dependency>
32+
<groupId>org.springframework</groupId>
33+
<artifactId>spring-webmvc</artifactId>
34+
<version>${spring.version}</version>
35+
</dependency>
36+
<dependency>
37+
<groupId>org.springframework.boot</groupId>
38+
<artifactId>spring-boot-starter-web</artifactId>
39+
<version>${spring-boot.version}</version>
40+
</dependency>
1341
<dependency>
1442
<groupId>junit</groupId>
1543
<artifactId>junit</artifactId>
1644
<scope>test</scope>
1745
</dependency>
46+
<dependency>
47+
<groupId>org.mockito</groupId>
48+
<artifactId>mockito-core</artifactId>
49+
<scope>test</scope>
50+
</dependency>
51+
<dependency>
52+
<groupId>org.apache.httpcomponents</groupId>
53+
<artifactId>httpclient</artifactId>
54+
<version>4.5.2</version>
55+
</dependency>
1856
</dependencies>
57+
58+
<build>
59+
<plugins>
60+
<plugin>
61+
<groupId>org.springframework.boot</groupId>
62+
<artifactId>spring-boot-maven-plugin</artifactId>
63+
<version>${spring-boot.version}</version>
64+
<executions>
65+
<execution>
66+
<goals>
67+
<goal>repackage</goal>
68+
</goals>
69+
</execution>
70+
</executions>
71+
</plugin>
72+
</plugins>
73+
</build>
1974
</project>
Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,42 @@
11
package com.iluwatar.api.gateway;
22

3+
import org.springframework.web.bind.annotation.RequestMapping;
4+
import org.springframework.web.bind.annotation.RestController;
5+
6+
import javax.annotation.Resource;
7+
38
/**
49
* The ApiGateway aggregates calls to microservices based on the needs of the individual clients.
510
*/
11+
@RestController
612
public class ApiGateway {
713

8-
private ImageService imageService = new ImageService();
9-
private PriceService priceService = new PriceService();
14+
@Resource
15+
private ImageClient imageClient;
16+
17+
@Resource
18+
private PriceClient priceClient;
1019

1120
/**
1221
* Retrieves product information that desktop clients need
1322
* @return Product information for clients on a desktop
1423
*/
24+
@RequestMapping("/desktop")
1525
public DesktopProduct getProductDesktop() {
1626
DesktopProduct desktopProduct = new DesktopProduct();
17-
desktopProduct.setImagePath(imageService.getImagePath());
18-
desktopProduct.setPrice(priceService.getPrice());
27+
desktopProduct.setImagePath(imageClient.getImagePath());
28+
desktopProduct.setPrice(priceClient.getPrice());
1929
return desktopProduct;
2030
}
2131

2232
/**
2333
* Retrieves product information that mobile clients need
2434
* @return Product information for clients on a mobile device
2535
*/
36+
@RequestMapping("/mobile")
2637
public MobileProduct getProductMobile() {
2738
MobileProduct mobileProduct = new MobileProduct();
28-
mobileProduct.setPrice(priceService.getPrice());
39+
mobileProduct.setPrice(priceClient.getPrice());
2940
return mobileProduct;
3041
}
3142
}
Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.iluwatar.api.gateway;
22

3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
36
/**
47
* With the Microservices pattern, a client may need data from multiple different microservices.
58
* If the client called each microservice directly, that could contribute to longer load times,
@@ -18,13 +21,15 @@
1821
*
1922
* <p>
2023
* This implementation shows what the API Gateway pattern could look like for an e-commerce site.
21-
* In this case, the (@link ImageService) and (@link PriceService) represent our microservices.
22-
* Customers viewing the site on a desktop device can see both price information and an image of
23-
* a product, so the (@link ApiGateway) calls both of the microservices and aggregates the data in
24-
* the (@link DesktopProduct) model. However, mobile users only see price information; they do not
25-
* see a product image. For mobile users, the (@link ApiGateway) only retrieves price information,
26-
* which it uses to populate the (@link MobileProduct).
24+
* The {@link ApiGateway} makes calls to the Image and Price microservices using the
25+
* {@link ImageClientImpl} and {@link PriceClientImpl} respectively. Customers viewing the site on a
26+
* desktop device can see both price information and an image of a product, so the {@link ApiGateway}
27+
* calls both of the microservices and aggregates the data in the {@link DesktopProduct} model.
28+
* However, mobile users only see price information; they do not see a product image. For mobile
29+
* users, the {@link ApiGateway} only retrieves price information, which it uses to populate the
30+
* {@link MobileProduct}.
2731
*/
32+
@SpringBootApplication
2833
public class App {
2934

3035
/**
@@ -34,13 +39,6 @@ public class App {
3439
* command line args
3540
*/
3641
public static void main(String[] args) {
37-
ApiGateway apiGateway = new ApiGateway();
38-
39-
DesktopProduct desktopProduct = apiGateway.getProductDesktop();
40-
System.out.println(String.format("Desktop Product \nPrice: %s\nImage path: %s",
41-
desktopProduct.getPrice(), desktopProduct.getImagePath()));
42-
43-
MobileProduct mobileProduct = apiGateway.getProductMobile();
44-
System.out.println(String.format("Mobile Product \nPrice: %s", mobileProduct.getPrice()));
42+
SpringApplication.run(App.class, args);
4543
}
4644
}

api-gateway/src/main/java/com/iluwatar/api/gateway/DesktopProduct.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@
44
* Encapsulates all of the information that a desktop client needs to display a product.
55
*/
66
public class DesktopProduct {
7-
7+
/**
8+
* The price of the product
9+
*/
810
private String price;
11+
12+
/**
13+
* The path to the image of the product
14+
*/
915
private String imagePath;
1016

1117
public String getPrice() {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.iluwatar.api.gateway;
2+
3+
/**
4+
* An interface used to communicate with the Image microservice
5+
*/
6+
public interface ImageClient {
7+
String getImagePath();
8+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.iluwatar.api.gateway;
2+
3+
import org.apache.http.client.methods.CloseableHttpResponse;
4+
import org.apache.http.client.methods.HttpGet;
5+
import org.apache.http.impl.client.CloseableHttpClient;
6+
import org.apache.http.impl.client.HttpClients;
7+
import org.apache.http.util.EntityUtils;
8+
import org.springframework.stereotype.Component;
9+
10+
import java.io.IOException;
11+
12+
/**
13+
* An adapter to communicate with the Image microservice
14+
*/
15+
@Component
16+
public class ImageClientImpl implements ImageClient{
17+
/**
18+
* Makes a simple HTTP Get request to the Image microservice
19+
* @return The path to the image
20+
*/
21+
@Override
22+
public String getImagePath() {
23+
String response = null;
24+
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
25+
HttpGet httpGet = new HttpGet("http://localhost:50005/image-path");
26+
try (CloseableHttpResponse httpResponse = httpClient.execute(httpGet)) {
27+
response = EntityUtils.toString(httpResponse.getEntity());
28+
}
29+
} catch (IOException e) {
30+
e.printStackTrace();
31+
}
32+
return response;
33+
}
34+
}

api-gateway/src/main/java/com/iluwatar/api/gateway/ImageService.java

Lines changed: 0 additions & 15 deletions
This file was deleted.

api-gateway/src/main/java/com/iluwatar/api/gateway/MobileProduct.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
* Encapsulates all of the information that mobile client needs to display a product.
55
*/
66
public class MobileProduct {
7-
7+
/**
8+
* The price of the product
9+
*/
810
private String price;
911

1012
public String getPrice() {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.iluwatar.api.gateway;
2+
3+
/**
4+
* An interface used to communicate with the Price microservice
5+
*/
6+
public interface PriceClient {
7+
String getPrice();
8+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.iluwatar.api.gateway;
2+
3+
import org.apache.http.client.methods.CloseableHttpResponse;
4+
import org.apache.http.client.methods.HttpGet;
5+
import org.apache.http.impl.client.CloseableHttpClient;
6+
import org.apache.http.impl.client.HttpClients;
7+
import org.apache.http.util.EntityUtils;
8+
import org.springframework.stereotype.Component;
9+
10+
import java.io.IOException;
11+
12+
/**
13+
* An adapter to communicate with the Price microservice
14+
*/
15+
@Component
16+
public class PriceClientImpl implements PriceClient{
17+
/**
18+
* Makes a simple HTTP Get request to the Price microservice
19+
* @return The price of the product
20+
*/
21+
@Override
22+
public String getPrice() {
23+
String response = null;
24+
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
25+
HttpGet httpGet = new HttpGet("http://localhost:50006/price");
26+
try (CloseableHttpResponse httpResponse = httpClient.execute(httpGet)) {
27+
response = EntityUtils.toString(httpResponse.getEntity());
28+
}
29+
} catch (IOException e) {
30+
e.printStackTrace();
31+
}
32+
return response;
33+
}
34+
}

0 commit comments

Comments
 (0)