7. Contract DSL
Prev |  | Next

# 7. Contract DSL

| Important
Remember that inside the contract file you have to provide the fully qualified name to the `Contract` class and the `make` static import i.e. `org.springframework.cloud.spec.Contract.make { …​ }`. You can also provide an import to the `Contract` class `import org.springframework.cloud.spec.Contract` and then call `Contract.make { …​ }`

Contract DSL is written in Groovy, but don’t be alarmed if you didn’t use Groovy before. Knowledge of the language is not really needed as our DSL uses only a tiny subset of it (namely literals, method calls and closures). What’s more the DSL is designed to be programmer-readable without any knowledge of the DSL itself - it’s statically typed.

| Tip
Spring Cloud Contract supports defining multiple contracts in a single file!

The Contract is present in the `spring-cloud-contract-spec` module of the Spring Cloud Contract Verifier repository.

Let’s look at full example of a contract definition.

    org.springframework.cloud.contract.spec.Contract.make {
    	request {
    		method 'PUT'
    		url '/api/12'
    		headers {
    			header 'Content-Type': 'application/vnd.org.springframework.cloud.contract.verifier.twitter-places-analyzer.v1+json'
    		}
    		body '''\
    		[{
    			"created_at": "Sat Jul 26 09:38:57 +0000 2014",
    			"id": 492967299297845248,
    			"id_str": "492967299297845248",
    			"text": "Gonna see you at Warsaw",
    			"place":
    			{
    				"attributes":{},
    				"bounding_box":
    				{
    					"coordinates":
    						[[
    							[-77.119759,38.791645],
    							[-76.909393,38.791645],
    							[-76.909393,38.995548],
    							[-77.119759,38.995548]
    						]],
    					"type":"Polygon"
    				},
    				"country":"United States",
    				"country_code":"US",
    				"full_name":"Washington, DC",
    				"id":"01fbe706f872cb32",
    				"name":"Washington",
    				"place_type":"city",
    				"url": "http://api.twitter.com/1/geo/id/01fbe706f872cb32.json"
    			}
    		}]
    	'''
    	}
    	response {
    		status 200
    	}
    }

Not all features of the DSL are used in example above. If you didn’t find what you are looking for, please check next paragraphs on this page.

> You can easily compile Contracts to WireMock stubs mapping using standalone maven command: `mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:convert`.

## 7.1 Limitations

| Warning
Spring Cloud Contract Verifier doesn’t support XML properly. Please use JSON or help us implement this feature.

| Warning
The support for the verification of size of JSON arrays is experimental. If you want to turn it on please provide the value of a system property `spring.cloud.contract.verifier.assert.size` equal to `true`. By default this feature is set to `false`. You can also provide the `assertJsonSize` property in the plugin configuration.

| Warning
Due to the fact that JSON structure can have any form it’s sometimes impossible to parse it properly when using the `value(consumer(…​), producer(…​))` notation when using that in GString. That’s why we highly recommend using the Groovy Map notation.

## 7.2 Common Top-Level elements

### 7.2.1 Description

You can add a `description` to your contract that is nothing else but an arbitrary text. Example:

    		org.springframework.cloud.contract.spec.Contract.make {
    			description('''
    given:
    	An input
    when:
    	Sth happens
    then:
    	Output
    ''')
    		}

### 7.2.2 Name

You can provide a name of your contract. Let’s assume that you’ve provided a name `should register a user`. If you do this then the name of the autogenerated test will be equal to `validate_should_register_a_user`. Also the name of the stub will be `should_register_a_user.json` in case of a WireMock stub.

| Important
Please ensure that the name doesn’t contain any characters that will make the generated test not possible to compile. Also remember that if you provide the same name for multiple contracts then your autogenerated tests will fail to compile and your generated stubs will override each other.

### 7.2.3 Ignoring contracts

If you want to ignore a contract you can either set a value of ignored contracts in the plugin configuration or just set the `ignored` property on the contract itself:

    org.springframework.cloud.contract.spec.Contract.make {
    	ignored()
    }

### 7.2.4 Passing values from files

Starting with version `1.2.0` it’s possible to pass values from files. Let’s assume that we have the following resources in our project.

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

And our contract looks like this:

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

    Contract.make {
    	request {
    		method('PUT')
    		headers {
    			contentType(applicationJson())
    		}
    		body(file("request.json"))
    		url("/1")
    	}
    	response {
    		status 200
    		body(file("response.json"))
    		headers {
    			contentType(textPlain())
    		}
    	}
    }

and the json files look like this:

request.json

    { "status" : "REQUEST" }

response.json

    { "status" : "RESPONSE" }

When test / stub generation takes place then the contents of the file will be passed to the body of request / response. All thanks to the `file(…​)` method. The argument of that method needs to be a file with location relative to the folder in which the contract lays.

### 7.2.5 HTTP Top-Level Elements

Following methods can be called in the top-level closure of a contract definition. Request and response are mandatory, priority is optional.

    org.springframework.cloud.contract.spec.Contract.make {
    	// Definition of HTTP request part of the contract
    	// (this can be a valid request or invalid depending
    	// on type of contract being specified).
    	request {
    		//...
    	}

    	// Definition of HTTP response part of the contract
    	// (a service implementing this contract should respond
    	// with following response after receiving request
    	// specified in "request" part above).
    	response {
    		//...
    	}

    	// Contract priority, which can be used for overriding
    	// contracts (1 is highest). Priority is optional.
    	priority 1
    }

## 7.3 Request

HTTP protocol requires only method and address to be specified in a request. The same information is mandatory in request definition of the Contract.

    org.springframework.cloud.contract.spec.Contract.make {
    	request {
    		// HTTP request method (GET/POST/PUT/DELETE).
    		method 'GET'

    		// Path component of request URL is specified as follows.
    		urlPath('/users')
    	}

    	response {
    		//...
    	}
    }

It is possible to specify whole `url` instead of just path, but `urlPath` is the recommended way as it makes the tests host-independent.

    org.springframework.cloud.contract.spec.Contract.make {
    	request {
    		method 'GET'

    		// Specifying `url` and `urlPath` in one contract is illegal.
    		url('http://localhost:8888/users')
    	}

    	response {
    		//...
    	}
    }

Request may contain query parameters, which are specified in a closure nested in a call to `urlPath` or `url`.

    org.springframework.cloud.contract.spec.Contract.make {
    	request {
    		//...

    		urlPath('/users') {

    			// Each parameter is specified in form
    			// `'paramName' : paramValue` where parameter value
    			// may be a simple literal or one of matcher functions,
    			// all of which are used in this example.
    			queryParameters {

    				// If a simple literal is used as value
    				// default matcher function is used (equalTo)
    				parameter 'limit': 100

    				// `equalTo` function simply compares passed value
    				// using identity operator (==).
    				parameter 'filter': equalTo("email")

    				// `containing` function matches strings
    				// that contains passed substring.
    				parameter 'gender': value(consumer(containing("[mf]")), producer('mf'))

    				// `matching` function tests parameter
    				// against passed regular expression.
    				parameter 'offset': value(consumer(matching("[0-9]+")), producer(123))

    				// `notMatching` functions tests if parameter
    				// does not match passed regular expression.
    				parameter 'loginStartsWith': value(consumer(notMatching(".{0,2}")), producer(3))
    			}
    		}

    		//...
    	}

    	response {
    		//...
    	}
    }

It may contain additional request headers…​

    org.springframework.cloud.contract.spec.Contract.make {
    	request {
    		//...

    		// Each header is added in form `'Header-Name' : 'Header-Value'`.
    		// there are also some helper methods
    		headers {
    			header 'key': 'value'
    			contentType(applicationJson())
    		}

    		//...
    	}

    	response {
    		//...
    	}
    }

…​and a request body.

    org.springframework.cloud.contract.spec.Contract.make {
    	request {
    		//...

    		// Currently only JSON format of request body is supported.
    		// Format will be determined from a header or body's content.
    		body '''{ "login" : "john", "name": "John The Contract" }'''
    	}

    	response {
    		//...
    	}
    }

Request may contain multipart elements. Just call the `multipart()` method.

    org.springframework.cloud.contract.spec.Contract contractDsl = org.springframework.cloud.contract.spec.Contract.make {
    	request {
    		method "PUT"
    		url "/multipart"
    		headers {
    			contentType('multipart/form-data;boundary=AaB03x')
    		}
    		multipart(
    				// key (parameter name), value (parameter value) pair
    				formParameter: $(c(regex('".+"')), p('"formParameterValue"')),
    				someBooleanParameter: $(c(regex(anyBoolean())), p('true')),
    				// a named parameter (e.g. with `file` name) that represents file with
    				// `name` and `content`. You can also call `named("fileName", "fileContent")`
    				file: named(
    						// name of the file
    						name: $(c(regex(nonEmpty())), p('filename.csv')),
    						// content of the file
    						content: $(c(regex(nonEmpty())), p('file content')))
    		)
    	}
    	response {
    		status 200
    	}
    }

In this example we defined parameters either directly by using the map notation, where the value can be a dynamic property (e.g. `formParameter: $(consumer(…​), producer(…​))`) or by using the `named(…​)` method that allows you to set a named parameter. A named parameter can set a `name` and `content`. You can call it either via a method with 2 arguments: e.g. `named("fileName", "fileContent")` or via a map notation `named(name: "fileName", content: "fileContent")`.

From this contract the generated test will look more or less like this:

    // given:
     MockMvcRequestSpecification request = given()
       .header("Content-Type", "multipart/form-data;boundary=AaB03x")
       .param("formParameter", "\"formParameterValue\"")
       .param("someBooleanParameter", "true")
       .multiPart("file", "filename.csv", "file content".getBytes());

    // when:
     ResponseOptions response = given().spec(request)
       .put("/multipart");

    // then:
     assertThat(response.statusCode()).isEqualTo(200);

The WireMock stub will look more or less like this:

    			'''
    {
      "request" : {
    	"url" : "/multipart",
    	"method" : "PUT",
    	"headers" : {
    	  "Content-Type" : {
    		"matches" : "multipart/form-data;boundary=AaB03x.*"
    	  }
    	},
    	"bodyPatterns" : [ {
    		"matches" : ".*--(.*)\\r\\nContent-Disposition: form-data; name=\\"formParameter\\"\\r\\n(Content-Type: .*\\r\\n)?(Content-Length: \\\\d+\\r\\n)?\\r\\n\\".+\\"\\r\\n--\\\\1.*"
      		}, {
        			"matches" : ".*--(.*)\\r\\nContent-Disposition: form-data; name=\\"someBooleanParameter\\"\\r\\n(Content-Type: .*\\r\\n)?(Content-Length: \\\\d+\\r\\n)?\\r\\n(true|false)\\r\\n--\\\\1.*"
      		}, {
    	  "matches" : ".*--(.*)\\r\\nContent-Disposition: form-data; name=\\"file\\"; filename=\\"[\\\\S\\\\s]+\\"\\r\\n(Content-Type: .*\\r\\n)?(Content-Length: \\\\d+\\r\\n)?\\r\\n[\\\\S\\\\s]+\\r\\n--\\\\1.*"
    	} ]
      },
      "response" : {
    	"status" : 200,
    	"transformers" : [ "response-template" ]
      }
    }
    	'''

## 7.4 Response

Minimal response must contain HTTP status code.

    org.springframework.cloud.contract.spec.Contract.make {
    	request {
    		//...
    	}
    	response {
    		// Status code sent by the server
    		// in response to request specified above.
    		status 200
    	}
    }

Besides status response may contain headers and body, which are specified the same way as in the request (see previous paragraph).

## 7.5 Dynamic properties

The contract can contain some dynamic properties - timestamps / ids etc. You don’t want to enforce the consumers to stub their clocks to always return the same value of time so that it gets matched by the stub. That’s why we allow you to provide the dynamic parts in your contracts in two ways. One is to pass them directly in the body and one to set them in a separate section called `testMatchers` and `stubMatchers`.

### 7.5.1 Dynamic properties inside the body

You can set the properties inside the body either via the `value` method

    value(consumer(...), producer(...))
    value(c(...), p(...))
    value(stub(...), test(...))
    value(client(...), server(...))

or if you’re using the Groovy map notation for body you can use the `$()` method

    $(consumer(...), producer(...))
    $(c(...), p(...))
    $(stub(...), test(...))
    $(client(...), server(...))

All of the aforementioned approaches are equal. That means that `stub` and `client` methods are aliases over the `consumer` method. Let’s take a closer look at what we can do with those values in the subsequent sections.

### 7.5.2 Regular expressions

You can use regular expressions to write your requests in Contract DSL. It is particularly useful when you want to indicate that a given response should be provided for requests that follow a given pattern. Also, you can use it when you need to use patterns and not exact values both for your test and your server side tests.

Please see the example below:

    org.springframework.cloud.contract.spec.Contract.make {
    	request {
    		method('GET')
    		url $(consumer(~/\/[0-9]{2}/), producer('/12'))
    	}
    	response {
    		status 200
    		body(
    				id: $(anyNumber()),
    				surname: $(
    						consumer('Kowalsky'),
    						producer(regex('[a-zA-Z]+'))
    				),
    				name: 'Jan',
    				created: $(consumer('2014-02-02 12:23:43'), producer(execute('currentDate(it)'))),
    				correlationId: value(consumer('5d1f9fef-e0dc-4f3d-a7e4-72d2220dd827'),
    						producer(regex('[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}'))
    				)
    		)
    		headers {
    			header 'Content-Type': 'text/plain'
    		}
    	}
    }

You can also provide only one side of the communication using a regular expression. If you do that then automatically we’ll provide the generated string that matches the provided regular expression. For example:

    org.springframework.cloud.contract.spec.Contract.make {
    	request {
    		method 'PUT'
    		url value(consumer(regex('/foo/[0-9]{5}')))
    		body([
    			requestElement: $(consumer(regex('[0-9]{5}')))
    		])
    		headers {
    			header('header', $(consumer(regex('application\\/vnd\\.fraud\\.v1\\+json;.*'))))
    		}
    	}
    	response {
    		status 200
    		body([
    			responseElement: $(producer(regex('[0-9]{7}')))
    		])
    		headers {
    			contentType("application/vnd.fraud.v1+json")
    		}
    	}
    }

In this example for request and response the opposite side of the communication will have the respective data generated.

Spring Cloud Contract comes with a series of predefined regular expressions that you can use in your contracts.

    protected static final Pattern TRUE_OR_FALSE = Pattern.compile(/(true|false)/)
    protected static final Pattern ONLY_ALPHA_UNICODE = Pattern.compile(/[\p{L}]*/)
    protected static final Pattern NUMBER = Pattern.compile('-?\\d*(\\.\\d+)?')
    protected static final Pattern IP_ADDRESS = Pattern.compile('([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])')
    protected static final Pattern HOSTNAME_PATTERN = Pattern.compile('((http[s]?|ftp):/)/?([^:/\\s]+)(:[0-9]{1,5})?')
    protected static final Pattern EMAIL = Pattern.compile('[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}')
    protected static final Pattern URL = UrlHelper.URL
    protected static final Pattern UUID = Pattern.compile('[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}')
    protected static final Pattern ANY_DATE = Pattern.compile('(\\d\\d\\d\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])')
    protected static final Pattern ANY_DATE_TIME = Pattern.compile('([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])')
    protected static final Pattern ANY_TIME = Pattern.compile('(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])')
    protected static final Pattern NON_EMPTY = Pattern.compile(/[\S\s]+/)
    protected static final Pattern NON_BLANK = Pattern.compile(/^\s*\S[\S\s]*/)
    protected static final Pattern ISO8601_WITH_OFFSET = Pattern.compile(/([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.\d{3})?(Z|[+-][01]\d:[0-5]\d)/)

    protected static Pattern anyOf(String... values){
    	return Pattern.compile(values.collect({"^$it\$"}).join("|"))
    }

    String onlyAlphaUnicode() {
    	return ONLY_ALPHA_UNICODE.pattern()
    }

    String number() {
    	return NUMBER.pattern()
    }

    String anyBoolean() {
    	return TRUE_OR_FALSE.pattern()
    }

    String ipAddress() {
    	return IP_ADDRESS.pattern()
    }

    String hostname() {
    	return HOSTNAME_PATTERN.pattern()
    }

    String email() {
    	return EMAIL.pattern()
    }

    String url() {
    	return URL.pattern()
    }

    String uuid(){
    	return UUID.pattern()
    }

    String isoDate() {
    	return ANY_DATE.pattern()
    }

    String isoDateTime() {
    	return ANY_DATE_TIME.pattern()
    }

    String isoTime() {
    	return ANY_TIME.pattern()
    }

    String iso8601WithOffset() {
    	return ISO8601_WITH_OFFSET.pattern()
    }

    String nonEmpty() {
    	return NON_EMPTY.pattern()
    }

    String nonBlank() {
    	return NON_BLANK.pattern()
    }

so in your contract you can use it like this

    Contract dslWithOptionalsInString = Contract.make {
    	priority 1
    	request {
    		method POST()
    		url '/users/password'
    		headers {
    			contentType(applicationJson())
    		}
    		body(
    				email: $(consumer(optional(regex(email()))), producer('abc@abc.com')),
    				callback_url: $(consumer(regex(hostname())), producer('http://partners.com'))
    		)
    	}
    	response {
    		status 404
    		headers {
    			contentType(applicationJson())
    		}
    		body(
    				code: value(consumer("123123"), producer(optional("123123"))),
    				message: "User not found by email = [${value(producer(regex(email())), consumer('not.existing@user.com'))}]"
    		)
    	}
    }

### 7.5.3 Passing optional parameters

It is possible to provide optional parameters in your contract. It’s only possible to have optional parameter for the:

- STUB side of the Request
- TEST side of the Response

Example:

    org.springframework.cloud.contract.spec.Contract.make {
    	priority 1
    	request {
    		method 'POST'
    		url '/users/password'
    		headers {
    			contentType(applicationJson())
    		}
    		body(
    				email: $(consumer(optional(regex(email()))), producer('abc@abc.com')),
    				callback_url: $(consumer(regex(hostname())), producer('http://partners.com'))
    		)
    	}
    	response {
    		status 404
    		headers {
    			header 'Content-Type': 'application/json'
    		}
    		body(
    				code: value(consumer("123123"), producer(optional("123123")))
    		)
    	}
    }

By wrapping a part of the body with the `optional()` method you are in fact creating a regular expression that should be present 0 or more times.

That way for the example above the following test would be generated if you pick Spock:

    """
     given:
      def request = given()
        .header("Content-Type", "application/json")
        .body('''{"email":"abc@abc.com","callback_url":"http://partners.com"}''')

     when:
      def response = given().spec(request)
        .post("/users/password")

     then:
      response.statusCode == 404
      response.header('Content-Type')  == 'application/json'
     and:
      DocumentContext parsedJson = JsonPath.parse(response.body.asString())
      assertThatJson(parsedJson).field("['code']").matches("(123123)?")
    """

and the following stub:

    '''
    {
      "request" : {
        "url" : "/users/password",
        "method" : "POST",
        "bodyPatterns" : [ {
          "matchesJsonPath" : "$[?(@.['email'] =~ /([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,6})?/)]"
        }, {
          "matchesJsonPath" : "$[?(@.['callback_url'] =~ /((http[s]?|ftp):\\\\/)\\\\/?([^:\\\\/\\\\s]+)(:[0-9]{1,5})?/)]"
        } ],
        "headers" : {
          "Content-Type" : {
            "equalTo" : "application/json"
          }
        }
      },
      "response" : {
        "status" : 404,
        "body" : "{\\"code\\":\\"123123\\",\\"message\\":\\"User not found by email == [not.existing@user.com]\\"}",
        "headers" : {
          "Content-Type" : "application/json"
        }
      },
      "priority" : 1
    }
    '''

### 7.5.4 Executing custom methods on server side

It is also possible to define a method call to be executed on the server side during the test. Such a method can be added to the class defined as "baseClassForTests" in the configuration. Example:

Contract

    org.springframework.cloud.contract.spec.Contract.make {
    	request {
    		method 'PUT'
    		url $(consumer(regex('^/api/[0-9]{2}$')), producer('/api/12'))
    		headers {
    			header 'Content-Type': 'application/json'
    		}
    		body '''\
    				[{
    					"text": "Gonna see you at Warsaw"
    				}]
    			'''
    	}
    	response {
    		body (
    				path: $(consumer('/api/12'), producer(regex('^/api/[0-9]{2}$'))),
    				correlationId: $(consumer('1223456'), producer(execute('isProperCorrelationId($it)')))
    		)
    		status 200
    	}
    }

Base class

    abstract class BaseMockMvcSpec extends Specification {

    	def setup() {
    		RestAssuredMockMvc.standaloneSetup(new PairIdController())
    	}

    	void isProperCorrelationId(Integer correlationId) {
    		assert correlationId == 123456
    	}

    	void isEmpty(String value) {
    		assert value == null
    	}

    }

| Important
You can’t use both a String and `execute` to perform concatenation. E.g. calling `header('Authorization', 'Bearer ' + execute('authToken()'))` will lead to improper results. To make this work just call `header('Authorization', execute('authToken()'))` and ensure that the `authToken()` method returns everything that you need.

The type of the object read from the JSON can be one of the followings depending on the JSON path:

- `String` if you point to a `String` value in a JSON
- `JSONArray` if you point to a `List` in a JSON
- `Map` if you point to a `Map` in a JSON
- proper `Number` if you point to `Integer`, `Double` etc. in a JSON
- `Boolean` if you point to a `Boolean` in a JSON

In the request part of the contract you can specify that the `body` should be taken from a method.

| Important
You have to provide both the consumer and the producer side and the `execute` part can be applied for the whole body. Not for parts of it!

Example:

    Contract contractDsl = Contract.make {
    	request {
    		method 'GET'
    		url '/something'
    		body(
    				$(c("foo"), p(execute("hashCode()")))
    		)
    	}
    	response {
    		status 200
    	}
    }

This will result in calling the `hashCode()` method in the request body. It would more or less like this:

    // given:
     MockMvcRequestSpecification request = given()
       .body(hashCode());

    // when:
     ResponseOptions response = given().spec(request)
       .get("/something");

    // then:
     assertThat(response.statusCode()).isEqualTo(200);

### 7.5.5 Referencing request from response

The best situation is to provide fixed values but sometimes you need to reference a request in your response. In order to do this you can profit from the `fromRequest()` method that allows you to reference a bunch of elements from the HTTP request. You can use the following options:

- `fromRequest().url()` - return the request URL and query parameters
- `fromRequest().query(String key)` - return the first query parameter with a given name
- `fromRequest().query(String key, int index)` - return the nth query parameter with a given name
- `fromRequest().path()` - return the full path
- `fromRequest().path(int index)` - return the nth path element
- `fromRequest().header(String key)` - return the first header with a given name
- `fromRequest().header(String key, int index)` - return the nth header with a given name
- `fromRequest().body()` - return the full request body
- `fromRequest().body(String jsonPath)` - return the element from the request that matches the JSON Path

Let’s take a look at the following contract

    Contract contractDsl = Contract.make {
    	request {
    		method 'GET'
    		url('/api/v1/xxxx') {
    			queryParameters {
    				parameter("foo", "bar")
    				parameter("foo", "bar2")
    			}
    		}
    		headers {
    			header(authorization(), "secret")
    			header(authorization(), "secret2")
    		}
    		body(foo: "bar", baz: 5)
    	}
    	response {
    		status 200
    		headers {
    			header(authorization(), "foo ${fromRequest().header(authorization())} bar")
    		}
    		body(
    				url: fromRequest().url(),
    				path: fromRequest().path(),
    				pathIndex: fromRequest().path(1),
    				param: fromRequest().query("foo"),
    				paramIndex: fromRequest().query("foo", 1),
    				authorization: fromRequest().header("Authorization"),
    				authorization2: fromRequest().header("Authorization", 1),
    				fullBody: fromRequest().body(),
    				responseFoo: fromRequest().body('$.foo'),
    				responseBaz: fromRequest().body('$.baz'),
    				responseBaz2: "Bla bla ${fromRequest().body('$.foo')} bla bla"
    		)
    	}
    }

Running a JUnit test generation will lead in creation of a test looking more or less like this

    // given:
     MockMvcRequestSpecification request = given()
       .header("Authorization", "secret")
       .header("Authorization", "secret2")
       .body("{\"foo\":\"bar\",\"baz\":5}");

    // when:
     ResponseOptions response = given().spec(request)
       .queryParam("foo","bar")
       .queryParam("foo","bar2")
       .get("/api/v1/xxxx");

    // then:
     assertThat(response.statusCode()).isEqualTo(200);
     assertThat(response.header("Authorization")).isEqualTo("foo secret bar");
    // and:
     DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
     assertThatJson(parsedJson).field("['fullBody']").isEqualTo("{\"foo\":\"bar\",\"baz\":5}");
     assertThatJson(parsedJson).field("['authorization']").isEqualTo("secret");
     assertThatJson(parsedJson).field("['authorization2']").isEqualTo("secret2");
     assertThatJson(parsedJson).field("['path']").isEqualTo("/api/v1/xxxx");
     assertThatJson(parsedJson).field("['param']").isEqualTo("bar");
     assertThatJson(parsedJson).field("['paramIndex']").isEqualTo("bar2");
     assertThatJson(parsedJson).field("['pathIndex']").isEqualTo("v1");
     assertThatJson(parsedJson).field("['responseBaz']").isEqualTo(5);
     assertThatJson(parsedJson).field("['responseFoo']").isEqualTo("bar");
     assertThatJson(parsedJson).field("['url']").isEqualTo("/api/v1/xxxx?foo=bar&foo=bar2");
     assertThatJson(parsedJson).field("['responseBaz2']").isEqualTo("Bla bla bar bla bla");

As you can see elements from the request have been properly referenced in the response.

The generated WireMock stub will look more or less like this:

    {
      "request" : {
        "urlPath" : "/api/v1/xxxx",
        "method" : "POST",
        "headers" : {
          "Authorization" : {
            "equalTo" : "secret2"
          }
        },
        "queryParameters" : {
          "foo" : {
            "equalTo" : "bar2"
          }
        },
        "bodyPatterns" : [ {
          "matchesJsonPath" : "$[?(@.['baz'] == 5)]"
        }, {
          "matchesJsonPath" : "$[?(@.['foo'] == 'bar')]"
        } ]
      },
      "response" : {
        "status" : 200,
        "body" : "{\"authorization\":\"{{{request.headers.Authorization.[0]}}}\",\"path\":\"{{{request.path}}}\",\"responseBaz\":{{{jsonpath this '$.baz'}}} ,\"param\":\"{{{request.query.foo.[0]}}}\",\"pathIndex\":\"{{{request.path.[1]}}}\",\"responseBaz2\":\"Bla bla {{{jsonpath this '$.foo'}}} bla bla\",\"responseFoo\":\"{{{jsonpath this '$.foo'}}}\",\"authorization2\":\"{{{request.headers.Authorization.[1]}}}\",\"fullBody\":\"{{{escapejsonbody}}}\",\"url\":\"{{{request.url}}}\",\"paramIndex\":\"{{{request.query.foo.[1]}}}\"}",
        "headers" : {
          "Authorization" : "{{{request.headers.Authorization.[0]}}};foo"
        },
        "transformers" : [ "response-template" ]
      }
    }

So sending a request as the one presented in the `request` part of the contract will lead in sending the following response body

    {
      "url" : "/api/v1/xxxx?foo=bar&foo=bar2",
      "path" : "/api/v1/xxxx",
      "pathIndex" : "v1",
      "param" : "bar",
      "paramIndex" : "bar2",
      "authorization" : "secret",
      "authorization2" : "secret2",
      "fullBody" : "{\"foo\":\"bar\",\"baz\":5}",
      "responseFoo" : "bar",
      "responseBaz" : 5,
      "responseBaz2" : "Bla bla bar bla bla"
    }

| Important

This feature will work only with WireMock having version greater or equal to 2.5.1. We’re using WireMock’s `response-template` response transformer. It’s using Handlebars to convert the Mustache `{{{ }}}` templates into proper values. Additionally we’re registering 2 helper functions. `escapejsonbody` - that escapes the request body in a format that can be embedded in a JSON. Another is `jsonpath` that for a given parameter knows how to find an object in the request body.

### 7.5.6 Dynamic properties in matchers sections

If you’ve been working with Pact this might seem familiar. Quite a few users are used to having a separation between the body and setting dynamic parts of your contract.

That’s why you can profit from two separate sections. One is called `stubMatchers` where you can define the dynamic values that should end up in a stub. You can set it in the `request` or `inputMessage` part of your contract. The other is called `testMatchers` which is present in the `response` or `outputMessage` side of the contract.

Currently we support only JSON Path based matchers with the following matching possibilities. For `stubMatchers`:

- `byEquality()` - the value taken from the response via the provided JSON Path needs to be equal to the provided value in the contract
- `byRegex(…​)` - the value taken from the response via the provided JSON Path needs to match the regex
- `byDate()` - the value taken from the response via the provided JSON Path needs to match the regex for ISO Date
- `byTimestamp()` - the value taken from the response via the provided JSON Path needs to match the regex for ISO DateTime
- `byTime()` - the value taken from the response via the provided JSON Path needs to match the regex for ISO Time

For `testMatchers`:

- `byEquality()` - the value taken from the response via the provided JSON Path needs to be equal to the provided value in the contract
- `byRegex(…​)` - the value taken from the response via the provided JSON Path needs to match the regex
- `byDate()` - the value taken from the response via the provided JSON Path needs to match the regex for ISO Date
- `byTimestamp()` - the value taken from the response via the provided JSON Path needs to match the regex for ISO DateTime
- `byTime()` - the value taken from the response via the provided JSON Path needs to match the regex for ISO Time
- `byType()` - the value taken from the response via the provided JSON Path needs to be of the same type as the type defined in the body of the response in the contract. `byType` can take a closure where you can set `minOccurrence` and `maxOccurrence`. That way you can assert on the size of the flattened collection. To check the size of an unflattened collection, use a custom method via `byCommand(…​)` testMatcher.

- `byCommand(…​)` - the value taken from the response via the provided JSON Path will be passed as an input to the custom method that you’re providing. E.g. `byCommand('foo($it)')` will result in calling a `foo` method to which the value matching the JSON Path will get passed.

  - The type of the object read from the JSON can be one of the followings depending on the JSON path:

    - `String` if you point to a `String` value in a JSON
    - `JSONArray` if you point to a `List` in a JSON
    - `Map` if you point to a `Map` in a JSON
    - proper `Number` if you point to `Integer`, `Double` etc. in a JSON
    - `Boolean` if you point to a `Boolean` in a JSON

Let’s take a look at the following example:

    Contract contractDsl = Contract.make {
    	request {
    		method 'GET'
    		urlPath '/get'
    		body([
    				duck: 123,
    				alpha: "abc",
    				number: 123,
    				aBoolean: true,
    				date: "2017-01-01",
    				dateTime: "2017-01-01T01:23:45",
    				time: "01:02:34",
    				valueWithoutAMatcher: "foo",
    				valueWithTypeMatch: "string",
    				key: [
    						'complex.key' : 'foo'
    				]
    		])
    		stubMatchers {
    			jsonPath('$.duck', byRegex("[0-9]{3}"))
    			jsonPath('$.duck', byEquality())
    			jsonPath('$.alpha', byRegex(onlyAlphaUnicode()))
    			jsonPath('$.alpha', byEquality())
    			jsonPath('$.number', byRegex(number()))
    			jsonPath('$.aBoolean', byRegex(anyBoolean()))
    			jsonPath('$.date', byDate())
    			jsonPath('$.dateTime', byTimestamp())
    			jsonPath('$.time', byTime())
    			jsonPath("\$.['key'].['complex.key']", byEquality())
    		}
    		headers {
    			contentType(applicationJson())
    		}
    	}
    	response {
    		status 200
    		body([
    				duck: 123,
    				alpha: "abc",
    				number: 123,
    				aBoolean: true,
    				date: "2017-01-01",
    				dateTime: "2017-01-01T01:23:45",
    				time: "01:02:34",
    				valueWithoutAMatcher: "foo",
    				valueWithTypeMatch: "string",
    				valueWithMin: [
    					1,2,3
    				],
    				valueWithMax: [
    					1,2,3
    				],
    				valueWithMinMax: [
    					1,2,3
    				],
    				valueWithMinEmpty: [],
    				valueWithMaxEmpty: [],
    				key: [
    				        'complex.key' : 'foo'
    				]
    		])
    		testMatchers {
    			// asserts the jsonpath value against manual regex
    			jsonPath('$.duck', byRegex("[0-9]{3}"))
    			// asserts the jsonpath value against the provided value
    			jsonPath('$.duck', byEquality())
    			// asserts the jsonpath value against some default regex
    			jsonPath('$.alpha', byRegex(onlyAlphaUnicode()))
    			jsonPath('$.alpha', byEquality())
    			jsonPath('$.number', byRegex(number()))
    			jsonPath('$.aBoolean', byRegex(anyBoolean()))
    			// asserts vs inbuilt time related regex
    			jsonPath('$.date', byDate())
    			jsonPath('$.dateTime', byTimestamp())
    			jsonPath('$.time', byTime())
    			// asserts that the resulting type is the same as in response body
    			jsonPath('$.valueWithTypeMatch', byType())
    			jsonPath('$.valueWithMin', byType {
    				// results in verification of size of array (min 1)
    				minOccurrence(1)
    			})
    			jsonPath('$.valueWithMax', byType {
    				// results in verification of size of array (max 3)
    				maxOccurrence(3)
    			})
    			jsonPath('$.valueWithMinMax', byType {
    				// results in verification of size of array (min 1 & max 3)
    				minOccurrence(1)
    				maxOccurrence(3)
    			})
    			jsonPath('$.valueWithMinEmpty', byType {
    				// results in verification of size of array (min 0)
    				minOccurrence(0)
    			})
    			jsonPath('$.valueWithMaxEmpty', byType {
    				// results in verification of size of array (max 0)
    				maxOccurrence(0)
    			})
    			// will execute a method `assertThatValueIsANumber`
    			jsonPath('$.duck', byCommand('assertThatValueIsANumber($it)'))
    			jsonPath("\$.['key'].['complex.key']", byEquality())
    		}
    		headers {
    			contentType(applicationJson())
    		}
    	}
    }

In this example we’re providing the dynamic portions of the contract in the matchers sections. For the request part you can see that for all fields but `valueWithoutAMatcher` we’re setting explicitly the values of regular expressions we’d like the stub to contain. For the `valueWithoutAMatcher` the verification will take place in the same way as without the usage of matchers - the test will perform an equality check in this case.

For the response side in the `testMatchers` section we’re defining all the dynamic parts in a similar manner. The only difference is that we have the `byType` matchers too. In that case we’re checking 4 fields in the way that we’re verifying whether the response from the test has a value whose JSON path matching the given field is of the same type as the one defined in the response body and:

- for `$.valueWithTypeMatch` - we’re just checking the whether the type is the same
- for `$.valueWithMin` - we’re checking the type and assert if the size is greater or equal to the min occurrence
- for `$.valueWithMax` - we’re checking the type and assert if the size is smaller or equal to the max occurrence
- for `$.valueWithMinMax` - we’re checking the type and assert if the size is between the min and max occurrence

The resulting test would look more or less like this (note that we’re separating the autogenerated assertions and the one from matchers with an `and` section):

    // given:
     MockMvcRequestSpecification request = given()
       .header("Content-Type", "application/json")
       .body("{\"duck\":123,\"alpha\":\"abc\",\"number\":123,\"aBoolean\":true,\"date\":\"2017-01-01\",\"dateTime\":\"2017-01-01T01:23:45\",\"time\":\"01:02:34\",\"valueWithoutAMatcher\":\"foo\",\"valueWithTypeMatch\":\"string\"}");

    // when:
     ResponseOptions response = given().spec(request)
       .get("/get");

    // then:
     assertThat(response.statusCode()).isEqualTo(200);
     assertThat(response.header("Content-Type")).matches("application/json.*");
    // and:
     DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
     assertThatJson(parsedJson).field("valueWithoutAMatcher").isEqualTo("foo");
    // and:
     assertThat(parsedJson.read("$.duck", String.class)).matches("[0-9]{3}");
     assertThat(parsedJson.read("$.duck", Integer.class)).isEqualTo(123);
     assertThat(parsedJson.read("$.alpha", String.class)).matches("[\\p{L}]*");
     assertThat(parsedJson.read("$.alpha", String.class)).isEqualTo("abc");
     assertThat(parsedJson.read("$.number", String.class)).matches("-?\\d*(\\.\\d+)?");
     assertThat(parsedJson.read("$.aBoolean", String.class)).matches("(true|false)");
     assertThat(parsedJson.read("$.date", String.class)).matches("(\\d\\d\\d\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])");
     assertThat(parsedJson.read("$.dateTime", String.class)).matches("([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])");
     assertThat(parsedJson.read("$.time", String.class)).matches("(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])");
     assertThat((Object) parsedJson.read("$.valueWithTypeMatch")).isInstanceOf(java.lang.String.class);
     assertThat((Object) parsedJson.read("$.valueWithMin")).isInstanceOf(java.util.List.class);
     assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMin", java.util.Collection.class)).hasSizeGreaterThanOrEqualTo(1);
     assertThat((Object) parsedJson.read("$.valueWithMax")).isInstanceOf(java.util.List.class);
     assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMax", java.util.Collection.class)).hasSizeLessThanOrEqualTo(3);
     assertThat((Object) parsedJson.read("$.valueWithMinMax")).isInstanceOf(java.util.List.class);
     assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMinMax", java.util.Collection.class)).hasSizeBetween(1, 3);
     assertThat((Object) parsedJson.read("$.valueWithMinEmpty")).isInstanceOf(java.util.List.class);
     assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMinEmpty", java.util.Collection.class)).hasSizeGreaterThanOrEqualTo(0);
     assertThat((Object) parsedJson.read("$.valueWithMaxEmpty")).isInstanceOf(java.util.List.class);
     assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMaxEmpty", java.util.Collection.class)).hasSizeLessThanOrEqualTo(0);
     assertThatValueIsANumber(parsedJson.read("$.duck"));

| Important
Notice that for the `byCommand` method we are calling the `assertThatValueIsANumber`. This method needs to be defined in the test base class or should be statically imported to your tests. Notice that the `byCommand` call was converted to `assertThatValueIsANumber(parsedJson.read("$.duck"));`. That means that we took the method name and passed the proper JSON path as a parameter to it.

and the WireMock stub like this:

    				'''
    {
      "request" : {
        "urlPath" : "/get",
        "method" : "POST",
        "headers" : {
          "Content-Type" : {
            "matches" : "application/json.*"
          }
        },
        "bodyPatterns" : [ {
          "matchesJsonPath" : "$[?(@.['valueWithoutAMatcher'] == 'foo')]"
        }, {
          "matchesJsonPath" : "$[?(@.['valueWithTypeMatch'] == 'string')]"
        }, {
          "matchesJsonPath" : "$.['list'].['some'].['nested'][?(@.['anothervalue'] == 4)]"
        }, {
          "matchesJsonPath" : "$.['list'].['someother'].['nested'][?(@.['anothervalue'] == 4)]"
        }, {
          "matchesJsonPath" : "$.['list'].['someother'].['nested'][?(@.['json'] == 'with value')]"
        }, {
          "matchesJsonPath" : "$[?(@.duck =~ /([0-9]{3})/)]"
        }, {
          "matchesJsonPath" : "$[?(@.duck == 123)]"
        }, {
          "matchesJsonPath" : "$[?(@.alpha =~ /([\\\\p{L}]*)/)]"
        }, {
          "matchesJsonPath" : "$[?(@.alpha == 'abc')]"
        }, {
          "matchesJsonPath" : "$[?(@.number =~ /(-?\\\\d*(\\\\.\\\\d+)?)/)]"
        }, {
          "matchesJsonPath" : "$[?(@.aBoolean =~ /((true|false))/)]"
        }, {
          "matchesJsonPath" : "$[?(@.date =~ /((\\\\d\\\\d\\\\d\\\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01]))/)]"
        }, {
          "matchesJsonPath" : "$[?(@.dateTime =~ /(([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9]))/)]"
        }, {
          "matchesJsonPath" : "$[?(@.time =~ /((2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9]))/)]"
        }, {
          "matchesJsonPath" : "$.list.some.nested[?(@.json =~ /(.*)/)]"
        } ]
      },
      "response" : {
        "status" : 200,
        "body" : "{\\"date\\":\\"2017-01-01\\",\\"dateTime\\":\\"2017-01-01T01:23:45\\",\\"number\\":123,\\"aBoolean\\":true,\\"duck\\":123,\\"alpha\\":\\"abc\\",\\"valueWithMin\\":[1,2,3],\\"time\\":\\"01:02:34\\",\\"valueWithTypeMatch\\":\\"string\\",\\"valueWithMax\\":[1,2,3],\\"valueWithMinMax\\":[1,2,3],\\"valueWithoutAMatcher\\":\\"foo\\"}",
        "headers" : {
          "Content-Type" : "application/json"
        }
      }
    }
    '''

| Important
If you use a `matcher` then the part of the request / response that the `matcher` is addressing via the JSON Path will get removed from assertion. In case of verifying a collection you have to create matchers for all elements of the collection.

Let’s look at the following example:

    Contract.make {
        request {
            method 'GET'
            url("/foo")
        }
        response {
            status 200
            body(events: [[
                                     operation          : 'EXPORT',
                                     eventId            : '16f1ed75-0bcc-4f0d-a04d-3121798faf99',
                                     status             : 'OK'
                             ], [
                                     operation          : 'INPUT_PROCESSING',
                                     eventId            : '3bb4ac82-6652-462f-b6d1-75e424a0024a',
                                     status             : 'OK'
                             ]
                    ]
            )
            testMatchers {
                jsonPath('$.events[0].operation', byRegex('.+'))
                jsonPath('$.events[0].eventId', byRegex('^([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$'))
                jsonPath('$.events[0].status', byRegex('.+'))
            }
        }
    }

This will lead in creating the following test (showing just the assertion section)

    and:
    	DocumentContext parsedJson = JsonPath.parse(response.body.asString())
    	assertThatJson(parsedJson).array("['events']").contains("['eventId']").isEqualTo("16f1ed75-0bcc-4f0d-a04d-3121798faf99")
    	assertThatJson(parsedJson).array("['events']").contains("['operation']").isEqualTo("EXPORT")
    	assertThatJson(parsedJson).array("['events']").contains("['operation']").isEqualTo("INPUT_PROCESSING")
    	assertThatJson(parsedJson).array("['events']").contains("['eventId']").isEqualTo("3bb4ac82-6652-462f-b6d1-75e424a0024a")
    	assertThatJson(parsedJson).array("['events']").contains("['status']").isEqualTo("OK")
    and:
    	assertThat(parsedJson.read("\$.events[0].operation", String.class)).matches(".+")
    	assertThat(parsedJson.read("\$.events[0].eventId", String.class)).matches("^([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})\$")
    	assertThat(parsedJson.read("\$.events[0].status", String.class)).matches(".+")

As you can see the assertion is malformed. That’s because only the first element of the array got asserted. In order to fix this it’s best to apply the assertion to the whole `$.events` collection and assert it via the `byCommand(…​)` method.

## 7.6 JAX-RS support

We support JAX-RS 2 Client API. Base class needs to define `protected WebTarget webTarget` and server initialization, right now the only option how to test JAX-RS API is to start a web server.

Request with a body needs to have a content type set otherwise `application/octet-stream` is going to be used.

In order to use JAX-RS mode, use the following settings:

    testMode == 'JAXRSCLIENT'

Example of a test API generated:

    '''
     // when:
      Response response = webTarget
        .path("/users")
        .queryParam("limit", "10")
        .queryParam("offset", "20")
        .queryParam("filter", "email")
        .queryParam("sort", "name")
        .queryParam("search", "55")
        .queryParam("age", "99")
        .queryParam("name", "Denis.Stepanov")
        .queryParam("email", "bob@email.com")
        .request()
        .method("GET");

      String responseAsString = response.readEntity(String.class);

     // then:
      assertThat(response.getStatus()).isEqualTo(200);
     // and:
      DocumentContext parsedJson = JsonPath.parse(responseAsString);
      assertThatJson(parsedJson).field("['property1']").isEqualTo("a");
    '''

## 7.7 Async support

If you’re using asynchronous communication on the server side (your controllers are returning `Callable`, `DeferredResult` etc. then inside your contract you have to provide in the `response` section a `async()` method. Example:

    org.springframework.cloud.contract.spec.Contract.make {
        request {
            method GET()
            url '/get'
        }
        response {
            status 200
            body 'Passed'
            async()
        }
    }

## 7.8 Working with Context Paths

Spring Cloud Contract supports context paths.

| Important
The only thing that changes in order to fully support context paths is the switch on the PRODUCER side. The autogenerated tests need to be using the EXPLICIT mode.

The consumer side remains untouched, in order for the generated test to pass you have to switch the EXPLICIT mode.

Maven.

    <plugin>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-contract-maven-plugin</artifactId>
        <version>${spring-cloud-contract.version}</version>
        <extensions>true</extensions>
        <configuration>
            <testMode>EXPLICIT</testMode>
        </configuration>
    </plugin>

Gradle.

    contracts {
    		testMode = 'EXPLICIT'
    }

That way you’ll generate a test that DOES NOT use MockMvc. It means that you’re generating real requests and you need to setup your generated test’s base class to work on a real socket.

Let’s imagine the following contract:

    org.springframework.cloud.contract.spec.Contract.make {
    	request {
    		method 'GET'
    		url '/my-context-path/url'
    	}
    	response {
    		status 200
    	}
    }

Here is an example of how to set up a base class and Rest Assured for everything to work correctly.

    import io.restassured.RestAssured;
    import org.junit.Before;
    import org.springframework.boot.context.embedded.LocalServerPort;
    import org.springframework.boot.test.context.SpringBootTest;

    @SpringBootTest(classes = ContextPathTestingBaseClass.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    class ContextPathTestingBaseClass {

    	@LocalServerPort int port;

    	@Before
    	public void setup() {
    		RestAssured.baseURI = "http://localhost";
    		RestAssured.port = this.port;
    	}
    }

That way all:

- all your requests in the autogenerated tests will be sent to the real endpoint with your context path included (e.g. `/my-context-path/url`)
- your contracts reflect that you have a context path, thus your generated stubs will also have that information (e.g. in the stubs you’ll see that you have too call `/my-context-path/url`)

## 7.9 Messaging Top-Level Elements

The DSL for messaging looks a little bit different than the one that focuses on HTTP.

### 7.9.1 Output triggered by a method

The output message can be triggered by calling a method (e.g. a Scheduler was started and a message was sent)

    def dsl = Contract.make {
    	// Human readable description
    	description 'Some description'
    	// Label by means of which the output message can be triggered
    	label 'some_label'
    	// input to the contract
    	input {
    		// the contract will be triggered by a method
    		triggeredBy('bookReturnedTriggered()')
    	}
    	// output message of the contract
    	outputMessage {
    		// destination to which the output message will be sent
    		sentTo('output')
    		// the body of the output message
    		body('''{ "bookName" : "foo" }''')
    		// the headers of the output message
    		headers {
    			header('BOOK-NAME', 'foo')
    		}
    	}
    }

In this case the output message will be sent to `output` if a method called `bookReturnedTriggered` will be executed. In the message publisher’s side we will generate a test that will call that method to trigger the message. On the consumer side you can use the `some_label` to trigger the message.

### 7.9.2 Output triggered by a message

The output message can be triggered by receiving a message.

    def dsl = Contract.make {
    	description 'Some Description'
    	label 'some_label'
    	// input is a message
    	input {
    		// the message was received from this destination
    		messageFrom('input')
    		// has the following body
    		messageBody([
    		        bookName: 'foo'
    		])
    		// and the following headers
    		messageHeaders {
    			header('sample', 'header')
    		}
    	}
    	outputMessage {
    		sentTo('output')
    		body([
    		        bookName: 'foo'
    		])
    		headers {
    			header('BOOK-NAME', 'foo')
    		}
    	}
    }

In this case the output message will be sent to `output` if a proper message will be received on the `input` destination. In the message publisher’s side we will generate a test that will send the input message to the defined destination. On the consumer side you can either send a message to the input destination or use the `some_label` to trigger the message.

### 7.9.3 Consumer / Producer

In HTTP you have a notion of `client`/`stub and `server`/`test` notation. You can use them also in messaging but we’re providing also the `consumer` and `produer` methods as presented below (note you can use either `$` or `value` methods to provide `consumer` and `producer` parts)

    Contract.make {
    	label 'some_label'
    	input {
    		messageFrom value(consumer('jms:output'), producer('jms:input'))
    		messageBody([
    				bookName: 'foo'
    		])
    		messageHeaders {
    			header('sample', 'header')
    		}
    	}
    	outputMessage {
    		sentTo $(consumer('jms:input'), producer('jms:output'))
    		body([
    				bookName: 'foo'
    		])
    	}
    }

## 7.10 Multiple contracts in one file

It’s possible to define multiple contracts in one file. An example of such a contract can look like this

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

    [
            Contract.make {
                name("should post a user")
                request {
                    method 'POST'
                    url('/users/1')
                }
                response {
                    status 200
                }
            },
            Contract.make {
                request {
                    method 'POST'
                    url('/users/2')
                }
                response {
                    status 200
                }
            }
    ]

In this example one contract has the `name` field and the other doesn’t. This will lead to generation of two tests that will look more or less like this:

    package org.springframework.cloud.contract.verifier.tests.com.hello;

    import com.example.TestBase;
    import com.jayway.jsonpath.DocumentContext;
    import com.jayway.jsonpath.JsonPath;
    import com.jayway.restassured.module.mockmvc.specification.MockMvcRequestSpecification;
    import com.jayway.restassured.response.ResponseOptions;
    import org.junit.Test;

    import static com.jayway.restassured.module.mockmvc.RestAssuredMockMvc.*;
    import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson;
    import static org.assertj.core.api.Assertions.assertThat;

    public class V1Test extends TestBase {

    	@Test
    	public void validate_should_post_a_user() throws Exception {
    		// given:
    			MockMvcRequestSpecification request = given();

    		// when:
    			ResponseOptions response = given().spec(request)
    					.post("/users/1");

    		// then:
    			assertThat(response.statusCode()).isEqualTo(200);
    	}

    	@Test
    	public void validate_withList_1() throws Exception {
    		// given:
    			MockMvcRequestSpecification request = given();

    		// when:
    			ResponseOptions response = given().spec(request)
    					.post("/users/2");

    		// then:
    			assertThat(response.statusCode()).isEqualTo(200);
    	}

    }

Notice that for the contract that has the `name` field the generated test method is named `validate_should_post_a_user`. For the one that doesn’t have the name it’s called `validate_withList_1`. It corresponds to the name of the file `WithList.groovy` and the index of the contract in the list.

The generated stubs will look like this

    should post a user.json
    1_WithList.json

As you can see the first file got the `name` parameter from the contract. The second got the name of the contract file `WithList.groovy` prefixed with the index (in this case contract had index `1` in the list of contracts in the file).

| Tip
As you can see it’s much better if you name your contracts since then your tests are far more meaningful.

Prev |  | Next
6. Stub Runner for Messaging | Home | 8. Customization