TL;DR
Consumer-Driven Contracts and in particular the use of Contract Testing can be a useful extension to any test suite. The definition of requirements from service consumers to the providing API ensures transparency about their expectations. On the one hand, this strengthens communication between the development teams of individual services and, on the other, service providers gain a better understanding of what their consumers actually need.
Contract testing also technically ensures that the professionally defined interface contracts are actually from all systems involved be observed. So if, despite the increased transparency and communication between the development teams brought about by the use of consumer-driven contracts, a Breaking Change are caused by a partner system, the Change technically prevented. It can no longer be deployed until compatibility with the interface is guaranteed again.
The problem: Breaking Api Changes
As a participant in a software development project, you have probably already been in a situation where an interface to a partner system suddenly stopped working as expected. This often happens because the API of the partner system is changed by the interface partner without consultation or prior notice - which means that a Breaking Change of the API. As a rule, this is noticed during the deployment in the integration tests. In the worst case, however, the affected API is not even considered in the test suite. It is then only noticed that the required interface no longer works when it is too late - in productive operation.
However, even if errors occur during the integration or smoke tests, this is anything but ideal. A (possibly time-consuming) analysis must first show whether the cause of the error is a breaking change in the partner system or a problem with the infrastructure. Wouldn't it be nice if there was a mechanism that forced all partner systems to announce their interface changes in good time - and that prevented unnegotiated interface changes? In this way, breaking API changes could be ruled out as a cause of errors, as they could no longer happen at all.
One solution: consumer-driven contracts
The good news is that this mechanism exists! The integration of technical interface contracts ("Interface Contracts", or "Contracts" for short) into the software development process, which automatically validated against the partner systems ("contract testing"). In addition, the use of such interface contracts and corresponding contract tests allows the principle of "Consumer-Driven Contracts (CDC) realize.
The underlying idea of consumer-driven contracts is that Consumer (callers of an API) first define their expectations of the API of an Providers (the provider of the API). These expectations then form the basis for the definition of interface contracts between the systems involved, compliance with which can be checked technically using contract tests. [1]
A contract is a collection of interactions between API consumer and API provider. An interaction describes the structure of a request and the associated response between the two actors. However, interactions describe not the expected behavior of a software, but only considers static aspects of communication with an interface. In other words, it defines WHICH functionality or resource can be requested and HOW.
In addition, contract tests ensure that there is a common understanding of the structure of the messages exchanged between the partner systems and that this is documented centrally. Another advantage of CDC is that the API provider can come to terms with the various needs of any consumers at an early stage in order to best meet the requests of all API consumers.
Tools
In general, no special tool is required for the implementation of CDC. However, tools such as Pact, Spring Cloud Contractetc. the implementation of CDC. They provide a technical framework for specifying and ensuring compliance with interface contracts through the use of contract tests. The Contract tests are called unit tests - and no longer as integration tests - and thus ensure that the early in the development cycle ensure compliance with the interface agreements.
Continuous review of compliance with the contracts
Since contract tests are realized as unit tests, they can be easily integrated into a CI/CD environment can be integrated. This allows APIs to be checked regularly and automatically for breaking changes. Without the use of contract tests, it would be possible to recognize that an interface is no longer compatible at the earliest at the time of the execution of smoke or integration tests - i.e. when a request is actually sent against the affected API endpoint.
The integration of contract tests into the software development process also forces the interface partners in a system landscape to communicate more closely "as a side effect", as everyone involved has to work on the design of and compliance with the interface in order to remain deployable themselves.
Something to consider
This communication is also important because with consumer-driven contracts, the consumers "determine" which interfaces they want. If many consumers make demands on the API without consultation, the provider may not be able to meet these demands. In addition, the complexity of dealing with changes is shifted from the consumers to the provider.
The provider also loses its own flexibility if it has to adapt exclusively to the requirements and change requests of the various consumers.
The implementation and maintenance of CDC initially means additional work, which can be off-putting. However, this additional effort can be worthwhile, especially for large projects with several parties, as the consistency of interfaces no longer has to be ensured manually. The use of CDC should therefore at least be considered and the costs weighed up against the benefits.
Contract testing with Pact
Pact (docs.pact.io) offers the possibility of creating interface contracts in a domain-specific language (Pact DSL) to create. To define this DSL, Pact supports various programming languages, including Java, Python, Ruby, JavaScript and C++ [2].
Procedure
- The consumer creates a technical interface contract, which contains the interactions expected with the interface.
- The expected requests from the contract are sent to a mock provider as part of a unit test. (Mock server provided by the Pact framework based on the contracts for the unit tests) is created. A contract (pact) file is created that contains the conditions of the interface contract.
- This file is transferred to the provider.
- Based on the contract, a consumer is simulated on the provider side, which makes the expected requests to the provider. This is done as part of unit tests that are generated from the contract.
- If all unit tests
- are successful, the provider can deploy its changes, as it is now clear that the consumer can communicate with it and process its responses.
- are not successful, the provider may not publish its changes, as the consumer would not be able to communicate with it and/or process its responses. The provider must now adapt its API so that it complies with the interface contract and the unit tests no longer fail.

Exchange of Pact files
The process described leaves open how the contracts are exchanged. Theoretically, they could simply be distributed "by hand" (by email, via an SCM, etc.) to the parties involved, but this would again create a manual administrative burden and make the desired technical support from CDC dependent on manual intervention. To simplify this process, the framework provides the so-called Pact Broker as an additional infrastructure component. The contracts are published by the consumer and retrieved by the provider via this broker so that the pact files do not have to be exchanged manually. The broker also has the advantage that the provider can send the results of its verification back to the broker, where they can in turn be queried by the consumer. In this way, the consumer can also find out whether the interface offered by the provider meets their requirements and whether they can deploy. [4]
In this first part of the blog post series on consumer-driven contracts, the basic principle of consumer-driven contracts was explained and Pact was introduced as a tool for creating and executing contract tests. The next part of the series will focus on the concrete Implementation of contract tests with Pact in Java using an example project. So it's worth staying tuned!
Sources
Cover picture: https://raw.githubusercontent.com/pact-foundation/pact-logo/master/media/logo-black.png
[1] https://www.martinfowler.com/articles/consumerDrivenContracts.html
[2] https://docs.pact.io/implementation_guides
[3] https://pactflow.io/how-pact-works/?utm_source=ossdocs&utm_campaign=getting_started#slide-5
[4] https://docs.pact.io/pact_broker/advanced_topics/provider_verification_results


