Consumer and provider binding in contract-testing
Tags: testing, pact
Published: 2021-02-22 16:45:21

I believe the fact that you are using contract-testing already has brought you here.

This approach seems simple for the first look but brings new questions and discoveries upon getting into it.

One of them is the understanding of how actually the contract corresponds with the consumer and provider.

Let's consider HTTP integration as a classic one and [Pact](https://docs.pact.io/) as a consumer-driven-contracts framework here but [Spring Cloud Contract](https://cloud.spring.io/spring-cloud-contract/) follows the same rules.

> The contract will be always used as a stub on the consumer side and as a set of validation criteria on the provider side

![1_TCch2EAD4JSDkFhWOhM3ew](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r59rie82h996z48ijj4a.png)

_How does it affect me?_

Each time you run consumer contract tests, it uses the contract data to start on it a stub server with **expectations** on a **request** and prepared stub data for **response**.

Each time you run provider tests, it uses the contract test to build a **request** to your actual server. Then it verifies the actual **response** against a set of validation criteria in the contact.

What's actually might be interesting here is to get an understanding of the concept of the strictness of the request/response data.

### Request

Consider, you expect that a server accepts your authorization header with a Bearer JWT token.

Speaking without code: _I expect when my app calls you with any valid JWT token you respond 200_
```yaml
Header:
  Authorization: Bearer eyJraWQiOiJ0aGlzLWlzLXJ
```
#### Consumer

You might not care about the strictness of the request data, i.e. you can use a stub that expects: _any JWT bearer token_

It means that matters only the **format** of data and not the data itself.

#### Provider

The request **must** be strict otherwise, the framework won't be able to build an actual request.

Options:
* Framework generates a random value
* Consumer prepare an example that will be used as a strict value

Having random values can be viable for some cases, but it leaves uncertainty as _the example_, that comes with the contract, will be non-informative.

In other words, the **data** of the request is crucial technically. And it is better to keep it strict as opposed to random.

That's why Pact framework has this option to provide the example for any data or not, btw.

### Response

Vice versa for the response.

The consumer must receive **strict** values in the response from the stub server.

The provider can respond with something that **matches** some data by a patter.

|          | request | response |
| -------- | ------- | -------- |
| consumer | not     | strict   |
| provider | strict  | not      |

### The reference in the contract

That's when you put the expectations like this:
```java
.matchHeader("Authorization", "Bearer.*", "Bearer eyJraWQiOiJ0aGlzLWlzLXJ")
```
Where the second parameter is the regexp that you expect to match the header.

It will be converted in the pact to the **scrict** values:

```json
"request" {
  "method": "GET",
  "path": "/your/path",
  "headers": {
          "Authorization": "Bearer eyJraWQiOiJ0aGlzLWlzLXJ"
    }
}
```
Plus `matchingRules` that come from the regexp property we passed above:
```json
"matchingRules": {
          "header": {
            "Authorization": {
              "matchers": [
                {
                  "match": "regex",
                  "regex": "Bearer.*"
                }
              ],
              "combine": "AND"
            }
...
```

Having the table above and the pact you can link them now and refer to this in your investigations.

|          | request | response |
| -------- | ------- | -------- |
| consumer | matchingRules| strict values   |
| provider | strict values | matchingRules|

Thinking about the format and data it is also right to consider it like this:

|          | request | response |
| -------- | ------- | -------- |
| consumer | format| data   |
| provider | data | format|

Sure, don't forget that for 'data' you can use random values.

### Conclusions

Here I'd like to remind you that contract testing is [the testing by the example approach](https://docs.pact.io/#consumer-driven-contracts). Thus, if you pay attention to the examples and understand the logic behind them, it will help you to have a great set of request/response samples that you can share with your teammates in combination with tests.

For more reference about the strict request and loose response read about [Robustness principle](https://en.wikipedia.org/wiki/Robustness_principle).

I think one of the most important parts of understanding contract testing is the behavior of stubs and verifications. Hope this note can help you to think through this concept.

PS. I wrote about the contract testing approach [here](https://medium.com/everon-engineering/contract-testing-in-everon-751e739038eb). Please join for more.