All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mework.cloud.spring-cloud-contract-docs.4.0.4.source-code._project-features-contract.adoc Maven / Gradle / Ivy

There is a newer version: 4.1.5
Show newest version
[[contract-dsl]]
== Contract DSL
include::_attributes.adoc[]

Spring Cloud Contract supports DSLs written in the following languages:

* Groovy
* YAML
* Java
* Kotlin

TIP: Spring Cloud Contract supports defining multiple contracts in a single file (In Groovy return a list instead of a single contract).

The following example shows a contract definition:

====
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy[tags=dsl_example,indent=0]
----

[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract_rest.yml[indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_rest.java[tags=class,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{verifier_core_path}/src/test/resources/kotlin/contract_rest.kts[tags=class,indent=0]
----
====

[TIP]
====
You can compile contracts to stubs mapping by using the following standalone Maven command:

----
mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:convert
----
====

[[contract-groovy]]
=== Contract DSL in Groovy

If you are not familiar with Groovy, do not worry. You can use Java syntax in the
Groovy DSL files as well.

If you decide to write the contract in Groovy, do not be alarmed if you have not used Groovy
before. Knowledge of the language is not really needed, as the Contract DSL uses only a
tiny subset of it (only literals, method calls, and closures). Also, the DSL is statically
typed, to make it programmer-readable without any knowledge of the DSL itself.

IMPORTANT: Remember that, inside the Groovy contract file, you have to provide the fully
qualified name to the `Contract` class and `make` static imports, such as
`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-java]]
=== Contract DSL in Java

To write a contract definition in Java, you need to create a class that implements either the `Supplier` interface (for a single contract) or `Supplier>` (for multiple contracts).

You can also write the contract definitions under `src/test/java` (for example, `src/test/java/contracts`) so that you do not have to modify the classpath of your project. In this case, you have to provide a new location of contract definitions to your Spring Cloud Contract plugin.

The following example (in both Maven and Gradle) has the contract definitions under `src/test/java`:

====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----

    org.springframework.cloud
    spring-cloud-contract-maven-plugin
    ${spring-cloud-contract.version}
    true
    
        src/test/java/contracts
    

----

[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
contracts {
	contractsDslDir = new File(project.rootDir, "src/test/java/contracts")
}
----
====

[[contract-kotlin]]
=== Contract DSL in Kotlin

To get started with writing contracts in Kotlin, you need to start with a (newly created) Kotlin Script file (`.kts`).
As with the Java DSL, you can put your contracts in any directory of your choice.
By default, the Maven plugin will look at the `src/test/resources/contracts` directory and Gradle plugin will
look at the `src/contractTest/resources/contracts` directory.

NOTE: Since 3.0.0, the Gradle plugin will also look at the legacy
directory `src/test/resources/contracts` for migration purposes. When contracts are found in this directory, a warning
will be logged during your build.

You need to explicitly pass the `spring-cloud-contract-spec-kotlin` dependency to your project plugin setup.
The following example (in both Maven and Gradle) shows how to do so:

====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----

    org.springframework.cloud
    spring-cloud-contract-maven-plugin
    ${spring-cloud-contract.version}
    true
    
        
    
    
        
            org.springframework.cloud
            spring-cloud-contract-spec-kotlin
            ${spring-cloud-contract.version}
        
    



        
        
            org.springframework.cloud
            spring-cloud-contract-spec-kotlin
            test
        

----

[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
buildscript {
    repositories {
        // ...
    }
	dependencies {
		classpath "org.springframework.cloud:spring-cloud-contract-gradle-plugin:${scContractVersion}"
	}
}

dependencies {
    // ...

    // Remember to add this for the DSL support in the IDE and on the consumer side
    testImplementation "org.springframework.cloud:spring-cloud-contract-spec-kotlin"
    // Kotlin versions are very particular down to the patch version. The  needs to be the same as you have imported for your project.
    testImplementation "org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:"
}
----
====

IMPORTANT: Remember that, inside the Kotlin Script file, you have to provide the fully qualified name to the `ContractDSL` class.
Generally you would use its contract function as follows: `org.springframework.cloud.contract.spec.ContractDsl.contract { ... }`.
You can also provide an import to the `contract` function (`import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract`) and then call `contract { ... }`.

[[contract-yml]]
=== Contract DSL in YAML

To see a schema of a YAML contract, visit the {docs-url}/reference/html/yml-schema.html[YML Schema] page.

[[contract-limitations]]
=== Limitations

WARNING: The support for verifying the size of JSON arrays is experimental. If you want
to turn it on, set the value of the following system property to `true`:
`spring.cloud.contract.verifier.assert.size`. By default, this feature is set to `false`.
You can also set the `assertJsonSize` property in the plugin configuration.

WARNING: Because JSON structure can have any form, it can be impossible to parse it
properly when using the Groovy DSL and the `value(consumer(...), producer(...))` notation in `GString`. That
is why you should use the Groovy Map notation.

[[contract-common-top-elements]]
=== Common Top-Level Elements

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

* <>
* <>
* <>
* <>
* <>
* <>

[[contract-dsl-description]]
==== Description

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

====
[source,groovy,indent=0,role="primary"]
.Groovy
----
include::{contract_spec_tests_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=description,indent=0]
----

[source,yaml,indent=0,role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract_rest.yml[indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_rest_with_tags.java[tags=description,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{contract_kotlin_spec_path}/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt[tags=description,indent=0]
----
====

[[contract-dsl-name]]
==== 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`.

IMPORTANT: 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:

====
[source,groovy,indent=0,role="primary"]
.Groovy
----
include::{contract_spec_tests_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=name,indent=0]
----

[source,yaml,indent=0,role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=name,indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_rest_with_tags.java[tags=name,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{contract_kotlin_spec_path}/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt[tags=name,indent=0]
----
====

[[contract-dsl-ignoring-contracts]]
==== 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:

====
[source,groovy,indent=0,role="primary"]
.Groovy
----
include::{contract_spec_tests_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=ignored,indent=0]
----

[source,yaml,indent=0,role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=ignored,indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_rest_with_tags.java[tags=ignored,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{contract_kotlin_spec_path}/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt[tags=ignored,indent=0]
----
====

[[contract-dsl-in-progress]]
==== Contracts in Progress

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

IMPORTANT: 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:

====
[source,groovy,indent=0,role="primary"]
.Groovy
----
include::{contract_spec_tests_path}/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy[tags=in_progress,indent=0]
----

[source,yaml,indent=0,role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=in_progress,indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_rest_with_tags.java[tags=in_progress,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{contract_kotlin_spec_path}/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt[tags=in_progress,indent=0]
----
====

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.

[[contract-dsl-passing-values-from-files]]
==== 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:

[source,bash,indent=0]
----
└── src
    └── test
        └── resources
            └── contracts
                ├── readFromFile.groovy
                ├── request.json
                └── response.json
----

Further assume that your contract is as follows:

====
[source,groovy,indent=0,role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/resources/classpath/readFromFile.groovy[indent=0]
----

[source,yaml,indent=0,role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract_from_file.yml[indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_rest_from_file.java[tags=class,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{verifier_core_path}/src/test/resources/kotlin/readFromFile.kts[tags=class,indent=0]
----
====

Further assume that the JSON files are as follows:

====
[source,json,indent=0,subs="verbatim,attributes",role="primary"]
.request.json
----
include::{verifier_core_path}/src/test/resources/classpath/request.json[indent=0]
----

[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.response.json
----
include::{verifier_core_path}/src/test/resources/classpath/response.json[indent=0]
----
====

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:

====
[source,groovy,indent=0,role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/resources/body_builder/worksWithPdf.groovy[indent=0]
----

[source,yaml,indent=0,role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract_pdf.yml[indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_rest_from_pdf.java[tags=class,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{contract_kotlin_spec_path}/src/test/resources/contracts/shouldWorkWithBinaryPayload.kts[tags=class,indent=0]
----
====

IMPORTANT: You should use this approach whenever you want to work with binary payloads,
both for HTTP and messaging.

[[contract-dsl-metadata]]
==== 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.

====
[source,groovy,indent=0,role="primary"]
.groovy
----
include::{standalone_samples_path}/http-server/src/test/resources/contracts/fraud/shouldReturnFraudStats.groovy[tags=metadata,indent=0]
----

[source,yaml,indent=0,role="secondary"]
.yml
----
include::{standalone_samples_path}/http-server/src/test/resources/contracts/yml/fraud/shouldReturnFraudStats.yml[tags=metadata,indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_rest_with_tags.java[tags=metadata,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.kotlin
----
include::{contract_kotlin_spec_path}/src/test/kotlin/org/springframework/cloud/contract/spec/ContractTests.kt[tags=metadata,indent=0]
----
====

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

////
include::{project-root}/docs/target/metadata.adoc[indent=0]
////

[[features-http]]
== 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.

[[contract-dsl-http-top-level-elements]]
=== HTTP Top-Level Elements

You can call the following methods in the top-level closure of a contract definition:

* `request`: Mandatory
* `response` : Mandatory
* `priority`: Optional

The following example shows how to define an HTTP request contract:

====
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=http_dsl,indent=0]
----

[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=priority,indent=0]
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
...
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=response,indent=0]
...
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=http_dsl,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=http_dsl,indent=0]
----
====

IMPORTANT: If you want to make your contract have a higher priority,
you need to pass a lower number to the `priority` tag or method. For example, a `priority` with
a value of `5` has higher priority than a `priority` with a value of `10`.

[[contract-dsl-request]]
=== HTTP Request

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

The following example shows a contract for a request:

====
[source,groovy,indent=0,role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=request,indent=0]
----

[source,yaml,indent=0,role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request_obligatory,indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=request,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=request,indent=0]
----
====

You can specify an absolute rather than a relative `url`, but using `urlPath` is
the recommended way, as doing so makes the tests be host-independent.

The following example uses `url`:

====
[source,groovy,indent=0,role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=url,indent=0]
----

[source,yaml,indent=0,role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract_rest_with_path.yml[tags=url_path,indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=url,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=url,indent=0]
----
====

`request` may contain query parameters, as the following example (which uses `urlPath`) shows:

====
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=urlpath,indent=0]
----

[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
...
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=query_params,indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=urlpath,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=urlpath,indent=0]
----
====

`request` can contain additional request headers, as the following example shows:

====
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=headers,indent=0]
----

[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
...
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=headers,indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=headers,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=headers,indent=0]
----
====

`request` may contain additional request cookies, as the following example shows:

====
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=cookies,indent=0]
----

[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
...
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=cookies,indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=cookies,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=cookies,indent=0]
----
====

`request` may contain a request body, as the following example shows:

====
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=body,indent=0]
----

[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=request,indent=0]
...
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=body,indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=body,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=body,indent=0]
----
====

`request` can contain multipart elements. To include multipart elements, use the
`multipart` method/section, as the following examples show:

====
[source,groovy,indent=0,role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy[tags=multipartdsl,indent=0]
----

[source,yaml,indent=0,role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract_multipart.yml[indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_multipart.java[tags=class,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{verifier_core_path}/src/test/resources/kotlin/multipart.kts[tags=class,indent=0]
----
====

In the preceding example, we defined parameters in either of two ways:

.Coded DSL
* Directly, by using the map notation, where the value can be a dynamic property (such as
`formParameter: $(consumer(...), producer(...))`).
* By using the `named(...)` method that lets you set a named parameter. A named parameter
can set a `name` and `content`. You can call it either by using a method with two arguments,
such as `named("fileName", "fileContent")`, or by using a map notation, such as
`named(name: "fileName", content: "fileContent")`.

.YAML
* The multipart parameters are set in the `multipart.params` section.
* The named parameters (the `fileName` and `fileContent` for a given parameter name)
can be set in the `multipart.named` section. That section contains
the `paramName` (the name of the parameter), `fileName` (the name of the file),
`fileContent` (the content of the file) fields.
* The dynamic bits can be set in the `matchers.multipart` section.
** For parameters, use the `params` section, which can accept
`regex` or a `predefined` regular expression.
** For named parameters, use the `named` section where you first
define the parameter name with `paramName`. Then you can pass the
parametrization of either `fileName` or `fileContent` in a
`regex` or in a `predefined` regular expression.

IMPORTANT: For the `named(...)` section you always have to add a pair of
`value(producer(...), consumer(...))` calls. Just setting DSL properties such
as just `value(producer(...))` or just `file(...)` will not work.
Check this https://github.com/spring-cloud/spring-cloud-contract/issues/1886[issue] for more information.

From the contract in the preceding example, the generated test and stub look as follows:

====
[source,java,indent=0,subs="verbatim,attributes",role="primary"]
.Test
----
// 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);
----

[source,json,indent=0,subs="verbatim,attributes",role="secondary"]
.Stub
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockGroovyDslSpec.groovy[tags=multipartwiremock,indent=0]
----
====

[[contract-dsl-response]]
=== HTTP Response

The response must contain an HTTP status code and may contain other information. The
following code shows an example:

====
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=response,indent=0]
----

[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=response,indent=0]
...
include::{verifier_core_path}/src/test/resources/yml/contract.yml[tags=response_obligatory,indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=response,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=response,indent=0]
----
====

Besides status, the response may contain headers, cookies, and a body, which are
specified the same way as in the request (see <>).

TIP: In the Groovy DSL, you can reference the `org.springframework.cloud.contract.spec.internal.HttpStatus`
methods to provide a meaningful status instead of a digit. For example, you can call
`OK()` for a status `200` or `BAD_REQUEST()` for `400`.

[[contract-dsl-dynamic-properties]]
=== Dynamic properties

The contract can contain some dynamic properties: timestamps, IDs, and so on. You do not
want to force the consumers to stub their clocks to always return the same value of time
so that it gets matched by the stub.

For the Groovy DSL, you can provide the dynamic parts in your contracts
in two ways: pass them directly in the body or set them in a separate section called
`bodyMatchers`.

NOTE: Before 2.0.0, these were set by using `testMatchers` and `stubMatchers`.
See the https://github.com/spring-cloud/spring-cloud-contract/wiki/Spring-Cloud-Contract-2.0-Migration-Guide[migration guide] for more information.

For YAML, you can use only the `matchers` section.

IMPORTANT: Entries inside the `matchers` must reference existing elements of the payload. For more information, see https://github.com/spring-cloud/spring-cloud-contract/issues/722[this issue].

[[contract-dsl-dynamic-properties-in-body]]
==== Dynamic Properties inside the Body

IMPORTANT: This section is valid only for the Coded DSL (Groovy, Java, and so on). See the
<> section for YAML examples of a similar feature.

You can set the properties inside the body either with the `value` method or, if you use
the Groovy map notation, with `$()`. The following example shows how to set dynamic
properties with the value method:

====
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.value
----
value(consumer(...), producer(...))
value(c(...), p(...))
value(stub(...), test(...))
value(client(...), server(...))
----

[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.$
----
$(consumer(...), producer(...))
$(c(...), p(...))
$(stub(...), test(...))
$(client(...), server(...))
----
====

Both approaches work equally well. The `stub` and `client` methods are aliases over the `consumer`
method. Subsequent sections take a closer look at what you can do with those values.

[[contract-dsl-regex]]
==== Regular Expressions

IMPORTANT: This section is valid only for the Groovy DSL. See the
<> section for YAML examples of a similar feature.

You can use regular expressions to write your requests in the contract DSL. Doing so 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 regular expressions when you
need to use patterns and not exact values both for your tests and your server-side tests.

Make sure that regex matches a whole region of a sequence, as, internally,
https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html#matches[`Pattern.matches()`]
is called. For instance, `abc` does not match `aabc`, but `.abc` does.
There are several additional <> as well.

The following example shows how to use regular expressions to write a request:

====
[source,groovy,indent=0,role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=regex,indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=regex,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=regex,indent=0]
----
====

You can also provide only one side of the communication with a regular expression. If you
do so, then the contract engine automatically provides the generated string that matches
the provided regular expression. The following code shows an example for Groovy:

[source,groovy,indent=0]
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy[tags=dsl_one_side_data_generation_example,indent=0]
----

In the preceding example, the opposite side of the communication has the respective data
generated for request and response.

Spring Cloud Contract comes with a series of predefined regular expressions that you can
use in your contracts, as the following example shows:

[source,java,indent=0]
----
include::{contract_spec_path}/src/main/java/org/springframework/cloud/contract/spec/internal/RegexPatterns.java[tags=regexps,indent=0]
----

In your contract, you can use it as follows (example for the Groovy DSL):

[source,groovy,indent=0]
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy[tags=contract_with_regex,indent=0]
----

To make matters even simpler, you can use a set of predefined objects that automatically
assume that you want a regular expression to be passed.
All of those methods start with the `any` prefix, as follows:

[source,java,indent=0]
----
include::{contract_spec_path}/src/main/java/org/springframework/cloud/contract/spec/internal/RegexCreatingProperty.java[tags=regex_creating_props,indent=0]
----

The following example shows how you can reference those methods:

====
[source,groovy,indent=0,role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy[tags=regex_creating_props,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=regex_creating_props,indent=0]
----
====

[[contract-dsl-regex-limitations]]
===== Limitations

CAUTION: Due to certain limitations of the `Xeger` library that generates a string out of
a regex, do not use the `$` and `^` signs in your regex if you rely on automatic
generation. See https://github.com/spring-cloud/spring-cloud-contract/issues/899[Issue 899].

CAUTION: Do not use a `LocalDate` instance as a value for `$` (for example, `$(consumer(LocalDate.now()))`).
It causes a `java.lang.StackOverflowError`. Use `$(consumer(LocalDate.now().toString()))` instead.
See https://github.com/spring-cloud/spring-cloud-contract/issues/900[Issue 900].

[[contract-dsl-optional-params]]
==== Passing Optional Parameters

IMPORTANT: This section is valid only for Groovy DSL. See the
<> section for YAML examples of a similar feature.

You can provide optional parameters in your contract. However, you can provide
optional parameters only for the following:

* The STUB side of the Request
* The TEST side of the Response

The following example shows how to provide optional parameters:

====
[source,groovy,indent=0,role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=optionals,indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=optionals,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=optionals,indent=0]
----
====

By wrapping a part of the body with the `optional()` method, you create a regular
expression that must be present 0 or more times.

If you use Spock, the following test would be generated from the previous example:

====
[source,groovy,indent=0]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=optionals_test,indent=0]
----
====

The following stub would also be generated:

[source,groovy,indent=0]
----
include::{plugins_path}/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy[tags=wiremock,indent=0]
----

[[contract-dsl-custom-methods]]
==== Calling Custom Methods on the Server Side

IMPORTANT: This section is valid only for the Groovy DSL. See the
<> section for YAML examples of a similar feature.

You can define a method call that runs on the server side during the test. Such a
method can be added to the class defined as `baseClassForTests` in the configuration. The
following code shows an example of the contract portion of the test case:

====
[source,groovy,indent=0,role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy[tags=method,indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_docs_examples.java[tags=method,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{verifier_core_path}/src/test/resources/kotlin/contract_docs_examples.kts[tags=method,indent=0]
----
====

The following code shows the base class portion of the test case:

[source,groovy,indent=0]
----
include::{plugins_path}/spring-cloud-contract-gradle-plugin/src/test/resources/functionalTest/bootSimple/src/test/groovy/org/springframework/cloud/contract/verifier/twitter/places/BaseMockMvcSpec.groovy[tags=base_class,indent=0]
----

IMPORTANT: You cannot use both a `String` and `execute` to perform concatenation. For
example, calling `header('Authorization', 'Bearer ' + execute('authToken()'))` leads to
improper results. Instead, call `header('Authorization', execute('authToken()'))` and
ensure that the `authToken()` method returns everything you need.

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

* `String`: If you point to a `String` value in the JSON.
* `JSONArray`: If you point to a `List` in the JSON.
* `Map`: If you point to a `Map` in the JSON.
* `Number`: If you point to `Integer`, `Double`, and other numeric type in the JSON.
* `Boolean`: If you point to a `Boolean` in the JSON.

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

IMPORTANT: You must provide both the consumer and the producer side. The `execute` part
is applied for the whole body, not for parts of it.

The following example shows how to read an object from JSON:

[source,groovy,indent=0]
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy[tags=body_execute,indent=0]
----

The preceding example results in calling the `hashCode()` method in the request body.
It should resemble the following code:

[source,java,indent=0]
----
 // given:
  MockMvcRequestSpecification request = given()
    .body(hashCode());

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

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

[[contract-dsl-referencing-request-from-response]]
==== Referencing the Request from the Response

The best situation is to provide fixed values, but sometimes you need to reference a
request in your response.

If you write contracts in the Groovy DSL, you can use the `fromRequest()` method, which lets
you reference a bunch of elements from the HTTP request. You can use the following
options:

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

If you use the YAML contract definition or the Java one, you have to use the
https://handlebarsjs.com/[Handlebars] `{{{ }}}` notation with custom Spring Cloud Contract
functions to achieve this. In that case, you can use the following options:

* `{{{ request.url }}}`: Returns the request URL and query parameters.
* `{{{ request.query.key.[index] }}}`: Returns the nth query parameter with the given name.
For example, for a key of `thing`, the first entry is `{{{ request.query.thing.[0] }}}`
* `{{{ request.path }}}`: Returns the full path.
* `{{{ request.path.[index] }}}`: Returns the nth path element. For example,
the first entry is ```{{{ request.path.[0] }}}
* `{{{ request.headers.key }}}`: Returns the first header with the given name.
* `{{{ request.headers.key.[index] }}}`: Returns the nth header with the given name.
* `{{{ request.body }}}`: Returns the full request body.
* `{{{ jsonpath this 'your.json.path' }}}`: Returns the element from the request that
matches the JSON Path. For example, for a JSON path of `$.here`, use `{{{ jsonpath this '$.here' }}}`

Consider the following contract:

====
[source,groovy,indent=0,role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy[tags=template_contract,indent=0]
----

[source,yaml,indent=0,role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract_reference_request.yml[indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
package contracts.beer.rest;

import java.util.function.Supplier;

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

import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.map;

class shouldReturnStatsForAUser implements Supplier {

	@Override
	public Contract get() {
		return Contract.make(c -> {
			c.request(r -> {
				r.method("POST");
				r.url("/stats");
				r.body(map().entry("name", r.anyAlphaUnicode()));
				r.headers(h -> {
					h.contentType(h.applicationJson());
				});
			});
			c.response(r -> {
				r.status(r.OK());
				r.body(map()
						.entry("text",
								"Dear {{{jsonPath request.body '$.name'}}} thanks for your interested in drinking beer")
						.entry("quantity", r.$(r.c(5), r.p(r.anyNumber()))));
				r.headers(h -> {
					h.contentType(h.applicationJson());
				});
			});
		});
	}

}
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
package contracts.beer.rest

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

contract {
    request {
        method = method("POST")
        url = url("/stats")
        body(mapOf(
            "name" to anyAlphaUnicode
        ))
        headers {
            contentType = APPLICATION_JSON
        }
    }
    response {
        status = OK
        body(mapOf(
            "text" to "Don't worry ${fromRequest().body("$.name")} thanks for your interested in drinking beer",
            "quantity" to v(c(5), p(anyNumber))
        ))
        headers {
            contentType = fromRequest().header(CONTENT_TYPE)
        }
    }
}
----
====

Running a JUnit test generation leads to a test that resembles the following example:

====
[source,java,indent=0]
----
 // 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 should resemble the following example:

====
[source,json,indent=0]
----
{
  "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" ]
  }
}
----
====

Sending a request such as the one presented in the `request` part of the contract results
in sending the following response body:

====
[source,json,indent=0]
----
{
  "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 works only with WireMock versions greater than or equal
to 2.5.1. The Spring Cloud Contract Verifier uses WireMock's
`response-template` response transformer. It uses Handlebars to convert the Mustache `{{{ }}}` templates into
proper values. Additionally, it registers two helper functions:

* `escapejsonbody`: Escapes the request body in a format that can be embedded in JSON.
* `jsonpath`: For a given parameter, finds an object in the request body.

[[contract-dsl-matchers]]
==== Dynamic Properties in the Matchers Sections

If you work with https://docs.pact.io/[Pact], the following discussion may seem familiar.
Quite a few users are used to having a separation between the body and setting the
dynamic parts of a contract.

You can use the `bodyMatchers` section for two reasons:

* Define the dynamic values that should end up in a stub.
You can set it in the `request` part of your contract.
* Verify the result of your test.
This section is present in the `response` or `outputMessage` side of the
contract.

Currently, Spring Cloud Contract Verifier supports only JSON path-based matchers with the
following matching possibilities:

===== Coded DSL

For the stubs (in tests on the consumer's side):

* `byEquality()`: The value taken from the consumer's request in the provided JSON path must be
equal to the value provided in the contract.
* `byRegex(...)`: The value taken from the consumer's request in the provided JSON path must
match the regex. You can also pass the type of the expected matched value (for example, `asString()`, `asLong()`, and so on).
* `byDate()`: The value taken from the consumer's request in the provided JSON path must
match the regex for an ISO Date value.
* `byTimestamp()`: The value taken from the consumer's request in the provided JSON path must
match the regex for an ISO DateTime value.
* `byTime()`: The value taken from the consumer's request in the provided JSON path must
match the regex for an ISO Time value.

For the verification (in generated tests on the Producer's side):

* `byEquality()`: The value taken from the producer's response in the provided JSON path must be
equal to the provided value in the contract.
* `byRegex(...)`: The value taken from the producer's response in the provided JSON path must
match the regex.
* `byDate()`: The value taken from the producer's response in the provided JSON path must match
the regex for an ISO Date value.
* `byTimestamp()`: The value taken from the producer's response in the provided JSON path must
match the regex for an ISO DateTime value.
* `byTime()`: The value taken from the producer's response in the provided JSON path must match
the regex for an ISO Time value.
* `byType()`: The value taken from the producer's response in 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, in which you can set `minOccurrence` and `maxOccurrence`. For the
request side, you should use the closure to assert size of the collection.
That way, you can assert the size of the flattened collection. To check the size of an
unflattened collection, use a custom method with the `byCommand(...)` `testMatcher`.
* `byCommand(...)`: The value taken from the producer's response in the provided JSON path is
passed as an input to the custom method that you provide. For example,
`byCommand('thing($it)')` results in calling a `thing` method to which the value matching the
JSON Path gets passed. The type of the object read from the JSON can be one of the
following, depending on the JSON path:
** `String`: If you point to a `String` value.
** `JSONArray`: If you point to a `List`.
** `Map`: If you point to a `Map`.
** `Number`: If you point to `Integer`, `Double`, or another kind of number.
** `Boolean`: If you point to a `Boolean`.
* `byNull()`: The value taken from the response in the provided JSON path must be null.

===== YAML

NOTE: See the Groovy section for a detailed explanation of
what the types mean.

For YAML, the structure of a matcher resembles the following example:

[source,yml,indent=0]
----
- path: $.thing1
  type: by_regex
  value: thing2
  regexType: as_string
----

Alternatively, if you want to use one of the predefined regular expressions
`[only_alpha_unicode, number, any_boolean, ip_address, hostname,
email, url, uuid, iso_date, iso_date_time, iso_time, iso_8601_with_offset, non_empty,
non_blank]`, you can use something similar to the following example:

[source,yml,indent=0]
----
- path: $.thing1
  type: by_regex
  predefined: only_alpha_unicode
----

The following list shows the allowed list of `type` values:

* For `stubMatchers`:
** `by_equality`
** `by_regex`
** `by_date`
** `by_timestamp`
** `by_time`
** `by_type`
*** Two additional fields (`minOccurrence` and `maxOccurrence`) are accepted.
* For `testMatchers`:
** `by_equality`
** `by_regex`
** `by_date`
** `by_timestamp`
** `by_time`
** `by_type`
*** Two additional fields (`minOccurrence` and `maxOccurrence`) are accepted.
** `by_command`
** `by_null`

You can also define which type the regular expression corresponds to in the `regexType`
field. The following list shows the allowed regular expression types:

* `as_integer`
* `as_double`
* `as_float`
* `as_long`
* `as_short`
* `as_boolean`
* `as_string`

Consider the following example:

====
[source,groovy,indent=0,role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderWithMatchersSpec.groovy[tags=matchers,indent=0]
----

[source,yaml,indent=0,role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract_matchers.yml[indent=0]
----
====

In the preceding example, you can see the dynamic portions of the contract in the
`matchers` sections. For the request part, you can see that, for all fields but
`valueWithoutAMatcher`, the values of the regular expressions that the stub should
contain are explicitly set. For `valueWithoutAMatcher`, the verification takes place
in the same way as without the use of matchers. In that case, the test performs an
equality check.

For the response side in the `bodyMatchers` section, we define the dynamic parts in a
similar manner. The only difference is that the `byType` matchers are also present. The
verifier engine checks four fields to verify whether the response from the test
has a value for which the JSON path matches the given field, is of the same type as the one
defined in the response body, and passes the following check (based on the method being called):

* For `$.valueWithTypeMatch`, the engine checks whether the type is the same.
* For `$.valueWithMin`, the engine checks the type and asserts whether the size is greater
than or equal to the minimum occurrence.
* For `$.valueWithMax`, the engine checks the type and asserts whether the size is
smaller than or equal to the maximum occurrence.
* For `$.valueWithMinMax`, the engine checks the type and asserts whether the size is
between the minimum and maximum occurrence.

The resulting test resembles the following example (note that an `and` section
separates the autogenerated assertions and the assertion from matchers):

[source,java,indent=0]
----
 // 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\",\"key\":{\"complex.key\":\"foo\"}}");

 // 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+|\\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)).as("$.valueWithMin").hasSizeGreaterThanOrEqualTo(1);
  assertThat((Object) parsedJson.read("$.valueWithMax")).isInstanceOf(java.util.List.class);
  assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMax", java.util.Collection.class)).as("$.valueWithMax").hasSizeLessThanOrEqualTo(3);
  assertThat((Object) parsedJson.read("$.valueWithMinMax")).isInstanceOf(java.util.List.class);
  assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMinMax", java.util.Collection.class)).as("$.valueWithMinMax").hasSizeBetween(1, 3);
  assertThat((Object) parsedJson.read("$.valueWithMinEmpty")).isInstanceOf(java.util.List.class);
  assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMinEmpty", java.util.Collection.class)).as("$.valueWithMinEmpty").hasSizeGreaterThanOrEqualTo(0);
  assertThat((Object) parsedJson.read("$.valueWithMaxEmpty")).isInstanceOf(java.util.List.class);
  assertThat((java.lang.Iterable) parsedJson.read("$.valueWithMaxEmpty", java.util.Collection.class)).as("$.valueWithMaxEmpty").hasSizeLessThanOrEqualTo(0);
  assertThatValueIsANumber(parsedJson.read("$.duck"));
  assertThat(parsedJson.read("$.['key'].['complex.key']", String.class)).isEqualTo("foo");
----

IMPORTANT: Notice that, for the `byCommand` method, the example calls the
`assertThatValueIsANumber`. This method must be defined in the test base class or be
statically imported to your tests. Notice that the `byCommand` call was converted to
`assertThatValueIsANumber(parsedJson.read("$.duck"));`. That means that the engine took
the method name and passed the proper JSON path as a parameter to it.

The resulting WireMock stub is in the following example:

[source,json,indent=0]
----
include::{plugins_path}/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverterSpec.groovy[tags=matchers,indent=0]
----

IMPORTANT: If you use a `matcher`, the part of the request and response that the
`matcher` addresses with the JSON Path gets removed from the assertion. In the case of
verifying a collection, you must create matchers for *all* the elements of the
collection.

Consider the following example:

====
[source,groovy,indent=0]
----
Contract.make {
    request {
        method 'GET'
        url("/foo")
    }
    response {
        status OK()
        body(events: [[
                                 operation          : 'EXPORT',
                                 eventId            : '16f1ed75-0bcc-4f0d-a04d-3121798faf99',
                                 status             : 'OK'
                         ], [
                                 operation          : 'INPUT_PROCESSING',
                                 eventId            : '3bb4ac82-6652-462f-b6d1-75e424a0024a',
                                 status             : 'OK'
                         ]
                ]
        )
        bodyMatchers {
            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('.+'))
        }
    }
}
----
====

The preceding code leads to creating the following test (the code block shows only the assertion section):

====
[source,java,indent=0]
----
		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(".+")
----
====

Note that the assertion is malformed. Only the first element of the array got
asserted. To fix this, apply the assertion to the whole `$.events`
collection and assert it with the `byCommand(...)` method.

[[contract-dsl-async]]
=== Asynchronous Support

If you use asynchronous communication on the server side (your controllers are
returning `Callable`, `DeferredResult`, and so on), then, inside your contract, you must
provide an `async()` method in the `response` section. The following code shows an example:

====
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
----
org.springframework.cloud.contract.spec.Contract.make {
    request {
        method GET()
        url '/get'
    }
    response {
        status OK()
        body 'Passed'
        async()
    }
}
----

[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
.YAML
----
response:
    async: true
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
class contract implements Supplier> {

	@Override
	public Collection get() {
		return Collections.singletonList(Contract.make(c -> {
			c.request(r -> {
				// ...
			});
			c.response(r -> {
				r.async();
				// ...
			});
		}));
	}

}
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract

contract {
    request {
        // ...
    }
    response {
        async = true
        // ...
    }
}
----
====

You can also use the `fixedDelayMilliseconds` method or property to add delay to your stubs.
The following example shows how to do so:

====
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
----
org.springframework.cloud.contract.spec.Contract.make {
    request {
        method GET()
        url '/get'
    }
    response {
        status 200
        body 'Passed'
        fixedDelayMilliseconds 1000
    }
}
----

[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
.YAML
----
response:
    fixedDelayMilliseconds: 1000
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
class contract implements Supplier> {

	@Override
	public Collection get() {
		return Collections.singletonList(Contract.make(c -> {
			c.request(r -> {
				// ...
			});
			c.response(r -> {
				r.fixedDelayMilliseconds(1000);
				// ...
			});
		}));
	}

}
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract

contract {
    request {
        // ...
    }
    response {
        delay = fixedMilliseconds(1000)
        // ...
    }
}
----
====

[[contract-dsl-xml]]
=== XML Support for HTTP

For HTTP contracts, we also support using XML in the request and response body.
The XML body has to be passed within the `body` element
as a `String` or `GString`. Also, body matchers can be provided for
both the request and the response. In place of the `jsonPath(...)` method, the `org.springframework.cloud.contract.spec.internal.BodyMatchers.xPath`
method should be used, with the desired `xPath` provided as the first argument
and the appropriate `MatchingType` as the second argument. All the body matchers apart from `byType()` are supported.

The following example shows a Groovy DSL contract with XML in the response body:

====
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/XmlMethodBodyBuilderSpec.groovy[tags=xmlgroovy]
----

[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/contract_rest_xml.yml[indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
include::{verifier_core_path}/src/test/resources/contractsToCompile/contract_xml.java[tags=class,indent=0]
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::{verifier_core_path}/src/test/resources/kotlin/contract_xml.kts[tags=class,indent=0]
----
====

The following example shows an automatically generated test for XML in the response body:

====
[source,java,indent=0]
----
@Test
public void validate_xmlMatches() throws Exception {
	// given:
	MockMvcRequestSpecification request = given()
				.header("Content-Type", "application/xml");

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

	// then:
	assertThat(response.statusCode()).isEqualTo(200);
	// and:
	DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance()
					.newDocumentBuilder();
	Document parsedXml = documentBuilder.parse(new InputSource(
				new StringReader(response.getBody().asString())));
	// and:
	assertThat(valueFromXPath(parsedXml, "/test/list/elem/text()")).isEqualTo("abc");
	assertThat(valueFromXPath(parsedXml,"/test/list/elem[2]/text()")).isEqualTo("def");
	assertThat(valueFromXPath(parsedXml, "/test/duck/text()")).matches("[0-9]{3}");
	assertThat(nodeFromXPath(parsedXml, "/test/duck/xxx")).isNull();
	assertThat(valueFromXPath(parsedXml, "/test/alpha/text()")).matches("[\\p{L}]*");
	assertThat(valueFromXPath(parsedXml, "/test/*/complex/text()")).isEqualTo("foo");
	assertThat(valueFromXPath(parsedXml, "/test/duck/@type")).isEqualTo("xtype");
	}
----
====

==== XML Support for Namespaces
Namespaced XML is supported. However, any XPath expresssions used to select namespaced content must be updated.

Consider the following explicitly namespaced XML document:

[source,xml,indent=0]
----

    [email protected]

----
The XPath expression to select the email address is: `/ns1:customer/email/text()`.

WARNING: Beware as the unqualified expression (`/customer/email/text()`) results in `""`.

For content that uses an unqualified namespace, the expression is more verbose. Consider the following XML document that
uses an unqualified namespace:

[source,xml,indent=0]
----

    [email protected]

----
The XPath expression to select the email address is
```
*/[local-name()='customer' and namespace-uri()='http://demo.com/customer']/*[local-name()='email']/text()
```
WARNING: Beware, as the unqualified expressions (`/customer/email/text()` or `*/[local-name()='customer' and namespace-uri()='http://demo.com/customer']/email/text()`)
result in `""`. Even the child elements have to be referenced with the `local-name` syntax.

===== General Namespaced Node Expression Syntax
- Node using qualified namespace:
```
/
```
- Node using and defining an unqualified namespace:
```
/*[local-name=()='' and namespace-uri=()='']
```
NOTE: In some cases, you can omit the `namespace_uri` portion, but doing so may lead to ambiguity.

- Node using an unqualified namespace (one of its ancestor's defines the xmlns attribute):
```
/*[local-name=()='']
```


[[contract-dsl-multiple]]
=== Multiple Contracts in One File

You can define multiple contracts in one file. Such a contract might resemble the
following example:

====
[source,groovy,indent=0,role="primary"]
.Groovy
----
include::{plugins_path}/spring-cloud-contract-maven-plugin/src/test/projects/multiple-contracts/src/test/resources/contracts/com/hello/v1/WithList.groovy[lines=18..-1,indent=0]
----

[source,yaml,indent=0,role="secondary"]
.YAML
----
include::{verifier_core_path}/src/test/resources/yml/multiple_contracts.yml[indent=0]
----

[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.Java
----
class contract implements Supplier> {

	@Override
	public Collection get() {
		return Arrays.asList(
            Contract.make(c -> {
            	c.name("should post a user");
                // ...
            }), Contract.make(c -> {
                // ...
            }), Contract.make(c -> {
                // ...
            })
		);
	}

}
----

[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract

arrayOf(
    contract {
        name("should post a user")
        // ...
    },
    contract {
        // ...
    },
    contract {
        // ...
    }
}
----
====

In the preceding example, one contract has the `name` field and the other does not. This
leads to generation of two tests that look like the following:

====
[source,java,indent=0]
----
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`. The one that does not have the `name` field is 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 are shown in the following example:

====
[source]
----
should post a user.json
1_WithList.json
----
====

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, the contract had an index of `1` in the list of contracts in the file).

TIP: It is much better to name your contracts, because doing so makes
your tests far more meaningful.

[[contract-stateful-contracts]]
=== Stateful Contracts

Stateful contracts (also known as scenarios) are contract definitions that should be read
in order. This might be useful in the following situations:

* You want to invoke the contract in a precisely defined order, since you use Spring
Cloud Contract to test your stateful application.

TIP: We really discourage you from doing that, since contract tests should be stateless.

* You want the same endpoint to return different results for the same request.

To create stateful contracts (or scenarios), you need to
use the proper naming convention while creating your contracts. The convention
requires including an order number followed by an underscore. This works regardless
of whether you work with YAML or Groovy. The following listing shows an example:

====
[source,indent=0]
----
my_contracts_dir\
  scenario1\
    1_login.groovy
    2_showCart.groovy
    3_logout.groovy
----
====

Such a tree causes Spring Cloud Contract Verifier to generate WireMock's scenario with a
name of `scenario1` and the three following steps:

. `login`, marked as `Started` pointing to...
. `showCart`, marked as `Step1` pointing to...
. `logout`, marked as `Step2` (which closes the scenario).

You can find more details about WireMock scenarios at
https://wiremock.org/docs/stateful-behaviour/[https://wiremock.org/docs/stateful-behaviour/].




© 2015 - 2024 Weber Informatics LLC | Privacy Policy