This version is still in development and is not considered stable yet. For the latest stable version, please use spring-cloud-contract 4.1.4!

Common Top-Level Elements

The following sections describe the most common top-level elements:

Description

You can add a description to your contract. The description is arbitrary text. The following code shows an example:

Groovy
			org.springframework.cloud.contract.spec.Contract.make {
				description('''
given:
	An input
when:
	Sth happens
then:
	Output
''')
			}
YAML
description: Some description
name: some name
priority: 8
ignored: true
request:
  url: /foo
  queryParameters:
    a: b
    b: c
  method: PUT
  headers:
    foo: bar
    fooReq: baz
  body:
    foo: bar
  matchers:
    body:
      - path: $.foo
        type: by_regex
        value: bar
    headers:
      - key: foo
        regex: bar
response:
  status: 200
  headers:
    foo2: bar
    foo3: foo33
    fooRes: baz
  body:
    foo2: bar
    foo3: baz
    nullValue: null
  matchers:
    body:
      - path: $.foo2
        type: by_regex
        value: bar
      - path: $.foo3
        type: by_command
        value: executeMe($it)
      - path: $.nullValue
        type: by_null
        value: null
    headers:
      - key: foo2
        regex: bar
      - key: foo3
        command: andMeToo($it)
Java
Contract.make(c -> {
	c.description("Some description");
}));
Kotlin
contract {
	description = """
given:
	An input
when:
	Sth happens
then:
	Output
"""
}

Name

You can provide a name for your contract. Assume that you provide the following name: should register a user. If you do so, the name of the autogenerated test is validate_should_register_a_user. Also, the name of the stub in a WireMock stub is should_register_a_user.json.

You must ensure that the name does not contain any characters that make the generated test not compile. Also, remember that, if you provide the same name for multiple contracts, your autogenerated tests fail to compile and your generated stubs override each other.

The following example shows how to add a name to a contract:

Groovy
org.springframework.cloud.contract.spec.Contract.make {
	name("some_special_name")
}
YAML
name: some name
Java
Contract.make(c -> {
	c.name("some name");
}));
Kotlin
contract {
	name = "some_special_name"
}

Ignoring Contracts

If you want to ignore a contract, you can either set a value for ignored contracts in the plugin configuration or set the ignored property on the contract itself. The following example shows how to do so:

Groovy
org.springframework.cloud.contract.spec.Contract.make {
	ignored()
}
YAML
ignored: true
Java
Contract.make(c -> {
	c.ignored();
}));
Kotlin
contract {
	ignored = true
}

Contracts in Progress

A contract in progress does not generate tests on the producer side but does allow generation of stubs.

Use this feature with caution as it may lead to false positives, because you generate stubs for your consumers to use without actually having the implementation in place.

If you want to set a contract in progress, the following example shows how to do so:

Groovy
org.springframework.cloud.contract.spec.Contract.make {
	inProgress()
}
YAML
inProgress: true
Java
Contract.make(c -> {
	c.inProgress();
}));
Kotlin
contract {
	inProgress = true
}

You can set the value of the failOnInProgress Spring Cloud Contract plugin property to ensure that your build breaks when at least one contract in progress remains in your sources.

Passing Values from Files

Starting with version 1.2.0, you can pass values from files. Assume that you have the following resources in your project:

└── src
    └── test
        └── resources
            └── contracts
                ├── readFromFile.groovy
                ├── request.json
                └── response.json

Further assume that your contract is as follows:

Groovy
/*
 * Copyright 2013-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

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

Contract.make {
	request {
		method('PUT')
		headers {
			contentType(applicationJson())
		}
		body(file("request.json"))
		url("/1")
	}
	response {
		status OK()
		body(file("response.json"))
		headers {
			contentType(applicationJson())
		}
	}
}
YAML
request:
  method: GET
  url: /foo
  bodyFromFile: request.json
response:
  status: 200
  bodyFromFile: response.json
Java
import java.util.Collection;
import java.util.Collections;
import java.util.function.Supplier;

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

class contract_rest_from_file implements Supplier<Collection<Contract>> {

	@Override
	public Collection<Contract> get() {
		return Collections.singletonList(Contract.make(c -> {
			c.request(r -> {
				r.url("/foo");
				r.method(r.GET());
				r.body(r.file("request.json"));
			});
			c.response(r -> {
				r.status(r.OK());
				r.body(r.file("response.json"));
			});
		}));
	}

}
Kotlin
import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract

contract {
	request {
		url = url("/1")
		method = PUT
		headers {
			contentType = APPLICATION_JSON
		}
		body = bodyFromFile("request.json")
	}
	response {
		status = OK
		body = bodyFromFile("response.json")
		headers {
			contentType = APPLICATION_JSON
		}
	}
}

Further assume that the JSON files are as follows:

request.json
{
  "status": "REQUEST"
}
response.json
{
  "status": "RESPONSE"
}

When test or stub generation takes place, the contents of the request.json and response.json files are passed to the body of a request or a response. The name of the file needs to be a file in a location relative to the folder in which the contract resides.

If you need to pass the contents of a file in binary form, you can use the fileAsBytes method in the coded DSL or a bodyFromFileAsBytes field in YAML.

The following example shows how to pass the contents of binary files:

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

Contract.make {
	request {
		url("/1")
		method(PUT())
		headers {
			contentType(applicationOctetStream())
		}
		body(fileAsBytes("request.pdf"))
	}
	response {
		status 200
		body(fileAsBytes("response.pdf"))
		headers {
			contentType(applicationOctetStream())
		}
	}
}
YAML
request:
  url: /1
  method: PUT
  headers:
    Content-Type: application/octet-stream
  bodyFromFileAsBytes: request.pdf
response:
  status: 200
  bodyFromFileAsBytes: response.pdf
  headers:
    Content-Type: application/octet-stream
Java
import java.util.Collection;
import java.util.Collections;
import java.util.function.Supplier;

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

class contract_rest_from_pdf implements Supplier<Collection<Contract>> {

	@Override
	public Collection<Contract> get() {
		return Collections.singletonList(Contract.make(c -> {
			c.request(r -> {
				r.url("/1");
				r.method(r.PUT());
				r.body(r.fileAsBytes("request.pdf"));
				r.headers(h -> {
					h.contentType(h.applicationOctetStream());
				});
			});
			c.response(r -> {
				r.status(r.OK());
				r.body(r.fileAsBytes("response.pdf"));
				r.headers(h -> {
					h.contentType(h.applicationOctetStream());
				});
			});
		}));
	}

}
Kotlin
import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract

contract {
	request {
		url = url("/1")
		method = PUT
		headers {
			contentType = APPLICATION_OCTET_STREAM
		}
		body = bodyFromFileAsBytes("contracts/request.pdf")
	}
	response {
		status = OK
		body = bodyFromFileAsBytes("contracts/response.pdf")
		headers {
			contentType = APPLICATION_OCTET_STREAM
		}
	}
}
You should use this approach whenever you want to work with binary payloads, both for HTTP and messaging.

Metadata

You can add metadata to your contract. Via the metadata you can pass in configuration to extensions. Below you can find an example of using the wiremock key. Its value is a map whose key is stubMapping and value being WireMock’s StubMapping object. Spring Cloud Contract is able to patch parts of your generated stub mapping with your custom code. You may want to do that in order to add webhooks, custom delays or integrate with third party WireMock extensions.

java
Contract.make(c -> {
	c.metadata(MetadataUtil.map()
		.entry("wiremock", ContractVerifierUtil.map()
			.entry("stubMapping", "{ \"response\" : { \"fixedDelayMilliseconds\" : 2000 } }")));
}));
kotlin
contract {
	metadata("wiremock" to ("stubmapping" to """
{
  "response" : {
	"fixedDelayMilliseconds": 2000
  }
}"""))
}

In the following sections you can find examples of the supported metadata entries.

Contracts for HTTP

Spring Cloud Contract lets you verify applications that use REST or HTTP as a means of communication. Spring Cloud Contract verifies that, for a request that matches the criteria from the request part of the contract, the server provides a response that is in keeping with the response part of the contract. Subsequently, the contracts are used to generate WireMock stubs that, for any request matching the provided criteria, provide a suitable response.