Creating a Rest API is simple these days. To be able to change your API and still keep it working for all consumers is much harder. When using Consumer Contracts, you can let your API evolve and verify you can still uphold the contract of your consumers. In this presentation I will be demonstrating this by using Spring Cloud Contract.
9. @mikevanvendeloo
Consumer Driven Contracts to the rescue
Consumer Driven Contracts is a pattern that drives the
development of the Producer from its Consumers point of view.
10. @mikevanvendeloo
Terminology
A Contract is a collection of agreements between a client
(Consumer) and an API (Producer) that describes the
interactions that can take place between them.
Consumer: Service listening to messages or requesting API methods
Producer: Service sending messages or exposing an API
Contract: Agreement between producer and consumer how the API (method,
request and response) / message will look like
11. @mikevanvendeloo
Technology Radar
“The concept isn’t new, but with the mainstream
acceptance of microservices, we need to remind
people that consumer-driven contracts are an
essential part of a mature microservice testing
portfolio, enabling independent service
deployments.”
18. @mikevanvendeloo
You can easily compile Contracts to WireMock stubs mapping using standalone maven
command:
mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:convert
Producer side - Wiremock
26. @mikevanvendeloo
Set properties in the body
value(consumer(...), producer(...))
$(consumer(...), producer(...))
Reuse of request information in the response
fromRequest().body(String jsonPath)
Advanced contracts - Dynamic properties
27. @mikevanvendeloo
Test matchers
jsonPath('$.isbn', byRegex(number()))
jsonPath('$.returned', byRegex(anyBoolean()))
jsonPath('$.returndate, byRegex(byDate()))
Results in testcode
assertThat(parsedJson.read("$.isbn", String.class)).matches("-?d*(.d+)?");
assertThat(parsedJson.read("$.returned", String.class)).matches("(true|false)");
assertThat(parsedJson.read("$.returndate",
String.class)).matches("(dddd)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])");
Advanced contracts - Test matchers
28. @mikevanvendeloo
Ability to specify how the dynamic values should be generated by wiremock
jsonPath('$.isbn, byRegex(number()))
jsonPath('$.returned, byRegex(anyBoolean()))
jsonPath('$.returnDate, byDate())
{ "matchesJsonPath" : "$[?(@.isbn =~ /(-?d*(.d+)?)/)]"},
{ "matchesJsonPath" : "$[?(@.returned =~ /((true|false))/)]"},
{ "matchesJsonPath" : "$[?(@.returndate =~
/((dddd)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01]))/)]"}
Advanced contracts - Stub matchers
30. @mikevanvendeloo
Contract Repository
Sharing the contracts via a separate repository
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<configuration>
<contractsRepositoryUrl>http://link/to/your/nexus</contractsRepositoryUrl>
<contractDependency>
<groupId>net.vanvendeloo.demos.comiccollections</groupId>
<artifactId>contracts</artifactId>
</contractDependency>
</configuration>
</plugin>
31. @mikevanvendeloo
Contract Testing with messaging
Out of the box integration for using stubs with the following frameworks
● Spring Integration
● Spring Cloud Stream
● Apache Camel
● Spring AMQP
34. @mikevanvendeloo
Conclusions
● Communication is still the most important thing!
● CDC frameworks are still in development
● Spring Cloud Contract
○ integrates well with the Spring ecosystem
○ ensures reusable stubs
○ in the future, will provide improved tooling for non-Java
users