Skip to content

Commit b3bbd7f

Browse files
Phil EndsleyPhil Endsley
Phil Endsley
authored and
Phil Endsley
committed
feat:Step 1 - Add simple consumer calling provider
1 parent fb9ffd9 commit b3bbd7f

26 files changed

+1330
-0
lines changed

.gitignore

+33
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,36 @@
1+
consumer/.gradle
2+
build/
3+
!../gradle/wrapper/gradle-wrapper.jar
4+
!**/src/main/**/build/
5+
!**/src/test/**/build/
6+
7+
### STS ###
8+
.apt_generated
9+
.classpath
10+
.factorypath
11+
.project
12+
.settings
13+
.springBeans
14+
.sts4-cache
15+
16+
### IntelliJ IDEA ###
17+
.idea
18+
*.iws
19+
*.iml
20+
*.ipr
21+
out/
22+
!**/src/main/**/out/
23+
!**/src/test/**/out/
24+
25+
### NetBeans ###
26+
/nbproject/private/
27+
/nbbuild/
28+
/dist/
29+
/nbdist/
30+
/.nb-gradle/
31+
32+
### VS Code ###
33+
.vscode/
134
.gradle
235
/build/
336

.idea/.gitignore

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/vcs.xml

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

+54
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,57 @@
33
This workshop is setup with a number of steps that can be run through. Each step is in a branch, so to run through a
44
step of the workshop just check out the branch for that step (i.e. `git checkout step1`).
55

6+
7+
## Scenario
8+
9+
There are two components in scope for our workshop.
10+
11+
1. Product Catalog application (Consumer). It provides a console interface to query the Product service for product information.
12+
1. Product Service (Provider). Provides useful things about products, such as listing all products and getting the details of an individual product.
13+
14+
## Step 1 - Simple Consumer calling Provider
15+
16+
We need to first create an HTTP client to make the calls to our provider service:
17+
18+
![Simple Consumer](diagrams/workshop_step1.svg)
19+
20+
The Consumer has implemented the product service client which has the following:
21+
22+
- `GET /products` - Retrieve all products
23+
- `GET /products/{id}` - Retrieve a single product by ID
24+
25+
The diagram below highlights the interaction for retrieving a product with ID 10:
26+
27+
![Sequence Diagram](diagrams/workshop_step1_class-sequence-diagram.svg)
28+
29+
You can see the client interface we created in `consumer/src/main/au/com/dius/pactworkshop/consumer/ProductService.java`:
30+
31+
```java
32+
@Service
33+
public class ProductService {
34+
35+
private final RestTemplate restTemplate;
36+
37+
@Autowired
38+
public ProductService(RestTemplate restTemplate) {
39+
this.restTemplate = restTemplate;
40+
}
41+
42+
public List<Product> getAllProducts() {
43+
return restTemplate.exchange("/products",
44+
HttpMethod.GET,
45+
null,
46+
new ParameterizedTypeReference<List<Product>>(){}).getBody();
47+
}
48+
49+
public Product getProduct(String id) {
50+
return restTemplate.getForEntity("/products/{id}", Product.class, id).getBody();
51+
}
52+
}
53+
```
54+
55+
We can run the client with `./gradlew consumer:bootRun` - it should fail with the error below, because the Provider is not running.
56+
57+
```console
58+
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://localhost:8085/products": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect
59+
```

build.gradle

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
subprojects {
2+
apply plugin: 'java'
3+
4+
repositories {
5+
mavenCentral()
6+
}
7+
}

consumer/build.gradle

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
plugins {
2+
id 'org.springframework.boot' version '2.3.4.RELEASE'
3+
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
4+
}
5+
6+
group = 'au.com.dius.pactworkshop'
7+
version = '0.0.1-SNAPSHOT'
8+
sourceCompatibility = '11'
9+
10+
dependencies {
11+
implementation 'org.springframework.boot:spring-boot-starter'
12+
implementation 'org.springframework.boot:spring-boot-starter-web'
13+
14+
testImplementation('org.springframework.boot:spring-boot-starter-test') {
15+
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
16+
}
17+
testImplementation 'com.github.tomakehurst:wiremock:2.27.2'
18+
}
19+
20+
test {
21+
useJUnitPlatform()
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package au.com.dius.pactworkshop.consumer;
2+
3+
import org.springframework.beans.factory.annotation.Autowired;
4+
import org.springframework.boot.CommandLineRunner;
5+
import org.springframework.stereotype.Component;
6+
7+
import java.util.List;
8+
import java.util.Scanner;
9+
import java.util.stream.IntStream;
10+
11+
@Component
12+
public class ConsoleInterface implements CommandLineRunner {
13+
14+
private final ProductService productService;
15+
16+
private List<Product> products;
17+
18+
@Autowired
19+
ConsoleInterface(ProductService productService) {
20+
this.productService = productService;
21+
}
22+
23+
@Override
24+
public void run(String... args) {
25+
Scanner scanner = new Scanner(System.in);
26+
while (true) {
27+
printAllProducts();
28+
Integer choice = getUserChoice(scanner);
29+
if (choice == null || choice <= 0 || choice > products.size()) {
30+
System.out.println("Exiting...");
31+
break;
32+
}
33+
printProduct(choice);
34+
}
35+
}
36+
37+
private void printAllProducts() {
38+
products = productService.getAllProducts();
39+
System.out.println("\n\nProducts\n--------");
40+
IntStream.range(0, products.size())
41+
.forEach(index -> System.out.println(String.format("%d) %s", index + 1, products.get(index).getName())));
42+
}
43+
44+
private Integer getUserChoice(Scanner scanner) {
45+
System.out.print("Select item to view details: ");
46+
String choice = scanner.nextLine();
47+
return parseChoice(choice);
48+
}
49+
50+
private void printProduct(int index) {
51+
String id = products.get(index - 1).getId();
52+
Product product = productService.getProduct(id);
53+
54+
System.out.println("Product Details\n---------------");
55+
System.out.println(product);
56+
}
57+
58+
private Integer parseChoice(String choice) {
59+
try {
60+
return Integer.parseInt(choice);
61+
} catch (NumberFormatException e) {
62+
return null;
63+
}
64+
}
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package au.com.dius.pactworkshop.consumer;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
@SpringBootApplication
7+
public class ConsumerApplication {
8+
9+
public static void main(String[] args) {
10+
SpringApplication.run(ConsumerApplication.class, args);
11+
}
12+
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package au.com.dius.pactworkshop.consumer;
2+
3+
import java.util.Objects;
4+
5+
public class Product {
6+
7+
private String id;
8+
private String type;
9+
private String name;
10+
private String version;
11+
12+
public Product() {
13+
}
14+
15+
public Product(String id,
16+
String type,
17+
String name,
18+
String version) {
19+
this.id = id;
20+
this.type = type;
21+
this.name = name;
22+
this.version = version;
23+
}
24+
25+
public String getId() {
26+
return id;
27+
}
28+
29+
public void setId(String id) {
30+
this.id = id;
31+
}
32+
33+
public String getType() {
34+
return type;
35+
}
36+
37+
public void setType(String type) {
38+
this.type = type;
39+
}
40+
41+
public String getName() {
42+
return name;
43+
}
44+
45+
public void setName(String name) {
46+
this.name = name;
47+
}
48+
49+
public String getVersion() {
50+
return version;
51+
}
52+
53+
public void setVersion(String version) {
54+
this.version = version;
55+
}
56+
57+
@Override
58+
public boolean equals(Object o) {
59+
if (this == o) return true;
60+
if (o == null || getClass() != o.getClass()) return false;
61+
Product product = (Product) o;
62+
return Objects.equals(id, product.id) &&
63+
Objects.equals(type, product.type) &&
64+
Objects.equals(name, product.name) &&
65+
Objects.equals(version, product.version);
66+
}
67+
68+
@Override
69+
public int hashCode() {
70+
return Objects.hash(id, type, name, version);
71+
}
72+
73+
@Override
74+
public String toString() {
75+
return "Product{" +
76+
"id='" + id + '\'' +
77+
", type='" + type + '\'' +
78+
", name='" + name + '\'' +
79+
", version='" + version + '\'' +
80+
'}';
81+
}
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package au.com.dius.pactworkshop.consumer;
2+
3+
import org.springframework.beans.factory.annotation.Autowired;
4+
import org.springframework.core.ParameterizedTypeReference;
5+
import org.springframework.http.HttpMethod;
6+
import org.springframework.stereotype.Service;
7+
import org.springframework.web.client.RestTemplate;
8+
9+
import java.util.List;
10+
11+
@Service
12+
public class ProductService {
13+
14+
private final RestTemplate restTemplate;
15+
16+
@Autowired
17+
public ProductService(RestTemplate restTemplate) {
18+
this.restTemplate = restTemplate;
19+
}
20+
21+
public List<Product> getAllProducts() {
22+
return restTemplate.exchange("/products",
23+
HttpMethod.GET,
24+
null,
25+
new ParameterizedTypeReference<List<Product>>(){}).getBody();
26+
}
27+
28+
public Product getProduct(String id) {
29+
return restTemplate.getForEntity("/products/{id}", Product.class, id).getBody();
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package au.com.dius.pactworkshop.consumer;
2+
3+
import org.springframework.beans.factory.annotation.Value;
4+
import org.springframework.boot.web.client.RestTemplateBuilder;
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.context.annotation.Configuration;
7+
import org.springframework.web.client.RestTemplate;
8+
9+
@Configuration
10+
public class ProductServiceConfig {
11+
12+
@Bean
13+
RestTemplate productRestTemplate(@Value("${provider.port:8085}") int port) {
14+
return new RestTemplateBuilder().rootUri(String.format("http://localhost:%d", port)).build();
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
spring.main.web-application-type=NONE

0 commit comments

Comments
 (0)