Consumer Driven Contracts using Spring Cloud Contract

  1. Why do I need this?
  2. How to implement?
  3. Workshop
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.saggu</groupId>
<artifactId>service-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>service-provider</name>
<description>Service-provider</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2020.0.3</spring-cloud.version>
<spring-cloud-contract.version>3.0.1</spring-cloud-contract.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>

<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-verifier</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>3.0.3</version>
<extensions>true</extensions>
<configuration>
<testFramework>JUNIT5</testFramework>
</configuration>
</plugin>

<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>${spring-cloud-contract.version}</version>
<extensions>true</extensions>
<configuration>
<baseClassForTests>com.saggu.cdc.CdcBaseClass</baseClassForTests>
</configuration>
</plugin>

</plugins>
</build>

</project>

OrderController.java

package com.saggu.cdc;

import com.saggu.cdc.OrderService.Order;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import static java.util.Objects.isNull;
import static org.springframework.http.ResponseEntity.notFound;
import static org.springframework.http.ResponseEntity.ok;

@RestController
public class OrderController {

private final OrderService orderService;

public OrderController(OrderService orderService) {
this.orderService = orderService;
}

@GetMapping(value = "/orders/{orderId}", produces = "application/json")
public ResponseEntity<Order> getOrder(@PathVariable("orderId") String orderId) {
Order order = orderService.getOrder(orderId);
if (isNull(order)) {
return notFound().build();
}
return ok(order);
}
}

OrderService.java

package com.saggu.cdc;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

import static java.util.Objects.isNull;
import static org.springframework.http.ResponseEntity.notFound;
import static org.springframework.http.ResponseEntity.ok;

@Service
public class OrderService {

static Map<String, Order> orders = Map.of(
"1", new Order("1", "Sony TV", 500.00, 1),
"2", new Order("2", "Samsung TV", 480.00, 1),
"3", new Order("3", "Washing Machine", 1500.0, 1)
);

public Order getOrder(String orderId) {
return orders.get(orderId);
}

@Data
@AllArgsConstructor
static class Order {
private String orderId;
private String itemName;
private double price;
private int units;
}
}

CdcBaseClass.java

package com.saggu.cdc;

import io.restassured.module.mockmvc.RestAssuredMockMvc;
import org.junit.jupiter.api.BeforeEach;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;

@SpringBootTest(classes = ProviderApplication.class)
public abstract class CdcBaseClass {

@Autowired
OrderController orderController;

@MockBean
OrderService orderService;

@BeforeEach
public void setup() {
RestAssuredMockMvc.standaloneSetup(orderController);

Mockito.when(orderService.getOrder("1"))
.thenReturn(OrderService.orders.get("1"));
}
}

order_for_client1.groovy

package contracts

import org.springframework.cloud.contract.spec.Contract

Contract.make {

description "should return order by id=1"

request {
url "/orders/1"
method GET()
}

response {
status OK()
headers {
contentType applicationJson()
}
body(
"id": "1",
"itemName": "Sony TV",
"price": 500.0,
"units": 1
)
}
}

--

--

--

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Our Gitlab CI pipeline for Laravel applications

Laravel CI pipeline in Gitlab

Logical vs. Syntactical Errors in Code

My Journey to Kubernetes onto Bare Metal — Part 4: MetalLB

Download In ?PDF Visualizing Technology, Complete with Student CD Read %book !#ePub

Exploring Multi-level Weaknesses using Automated Chaos Experiments

5 factors to consider for deciding to build native mobile app or cross platform mobile app

Why working with UUIDs instead of IDs is better

Learn basics of Web3 with us 🦉

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Jasvinder S Saggu

Jasvinder S Saggu

More from Medium

Evolve Database Using Liquibase

Encrypting and Decrypting a message using Symmetric Keys with Java, explained step-by-step with…

How to Set Up Real-Time SDK Java Application with Maven on the Eclipse IDE

Authorisation with Spring Security — Part 1