Press "Enter" to skip to content

Consumer-Driven Contracts

Consumer-Driven Contracts is an interesting approach to the design and verification of API endpoints. The basic idea behind this is that the consumer decides how the API should work, not the server. Scary, isn’t it?

First, let’s clarify where this approach should and where it should not be used. It should be used for all the internal APIs in your backend, all your services, microservices etc. It should not be used for creating a public, external API, as it requires a cooperation between consumer and server and that is not possible in that scenario. Imagine that twitter would use this for their API, each developer who would like to use would be able to design its own version of API and twitter would have to somehow comply. And that is not possible in terms of work required and doesn’t make much sense.

Currently, there are few tools that help implement this approach, Pact and Spring Cloud Contract. Pact has implementations for many languages, like all the JVM, .NET, Ruby, JS, Go and Swift, where Spring Cloud Contract is focused on Spring JVM ecosystem.

The Contract

The basic idea is that consumer defines a contract where he describes the desired form of communication. That is request and response in detail. This contract is later used by the tools to verify if implementation complies with it.

The request consists of  URL, HTTP method, headers, body – everything that may be used in the HTTP request. It’s up to consumer what will be used here and in what form. If request body should be a JSON object, it should be defined completely here too.

The response consists of HTTP status, headers and body. As in the request case, if we use JSON, we have to describe it here too.

In Spring Cloud Contract, contracts are defined with groovy DSL. These contracts are stored in separate files and distributed any way we want. Here’s an example from the documentation:

 

In Pact, as far as I know, contracts are defined inside tests from which contract is later generated. Here is an example from the documentation of such test:

I have a contract, now what?

Now that we have a contract defined, we can use it to verify both sides of the communication. Both tools generate some sort of stubs/mocks of the other side, against which test are run for each contract.

For example, Spring Cloud Contract uses WireMock to create stub server for use on the client-side tests, tests that should be defined by the client-side developer – these are not generated. But on the server side, tests will be generated according to the contract. All that is required from the developer is to provide a base test class that will be extended by generated tests. This class is required so that all the necessary dependencies of your service will be provided in a way that you want, that means it is here where you can define mocks of the services, databases etc.

The final step

All that is left to do is to implement the server side. We now have complete knowledge of the desired API and tests that can prove if our implementation complies to the contracts. This makes things a bit easier, we know what we have to do and we have a way to verify it easily.

As you can see, the concept is not really complicated, it requires a bit more work than standard process of design – talking with each other and agreeing on something in one form of another – as some sort of document or something. But I think that small amount of additional work is worth it.

Personally, I plan to use this approach in future projects which will involve multiple services on the backend, I haven’t used it yet, but as the world is more and more focused on distributed application such as microservices, I think that some kind of verification of communication is required, and Consumer-Driven Contracts is a pretty good solution to this problem.


Also published on Medium.