[[features-rest-docs]]
= Working with REST Docs

include::partial$_attributes.adoc[]

You can use https://projects.spring.io/spring-restdocs[Spring REST Docs] to generate
documentation (for example, in Asciidoc format) for an HTTP API with Spring MockMvc,
WebTestClient, or RestAssured. At the same time that you generate documentation for your API, you can also
generate WireMock stubs by using Spring Cloud Contract WireMock. To do so, write your
normal REST Docs test cases and use `@AutoConfigureRestDocs` to have stubs be
automatically generated in the REST Docs output directory. The following UML diagram shows
the REST Docs flow:

[plantuml, rest-docs, png]
----
"API Producer"->"API Producer": Add Spring Cloud Contract (SCC) \nStub Runner dependency
"API Producer"->"API Producer": Set up stub jar assembly
"API Producer"->"API Producer": Write and set up REST Docs tests
"API Producer"->"Build": Run build
"Build"->"REST Docs": Generate API \ndocumentation
"REST Docs"->"SCC": Generate stubs from the \nREST Docs tests
"REST Docs"->"SCC": Generate contracts from the \nREST Docs tests
"Build"->"Build": Assemble stubs jar with \nstubs and contracts
"Build"->"Nexus / Artifactory": Upload contracts \nand stubs and the project arifact
"Build"->"API Producer": Build successful
"API Consumer"->"API Consumer": Add SCC Stub Runner \ndependency
"API Consumer"->"API Consumer": Write a SCC Stub Runner \nbased contract test
"SCC Stub Runner"->"Nexus / Artifactory": Test asks for [API Producer] stubs
"Nexus / Artifactory"->"SCC Stub Runner": Fetch the [API Producer] stubs
"SCC Stub Runner"->"SCC Stub Runner": Run in memory\n HTTP server stubs
"API Consumer"->"SCC Stub Runner": Send a request \nto the HTTP server stub
"SCC Stub Runner"->"API Consumer": Communication is correct
----

The following example uses `MockMvc`:

====
[source,java,indent=0]
----
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureRestDocs(outputDir = "target/snippets")
@AutoConfigureMockMvc
public class ApplicationTests {

	@Autowired
	private MockMvc mockMvc;

	@Test
	public void contextLoads() throws Exception {
		mockMvc.perform(get("/resource"))
				.andExpect(content().string("Hello World"))
				.andDo(document("resource"));
	}
}
----
====

This test generates a WireMock stub at `target/snippets/stubs/resource.json`. It matches
all `GET` requests to the `/resource` path. The same example with WebTestClient (used
for testing Spring WebFlux applications) would be as follows:

====
[source,java,indent=0]
----
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureRestDocs(outputDir = "target/snippets")
@AutoConfigureWebTestClient
public class ApplicationTests {

	@Autowired
	private WebTestClient client;

	@Test
	public void contextLoads() throws Exception {
		client.get().uri("/resource").exchange()
				.expectBody(String.class).isEqualTo("Hello World")
 				.consumeWith(document("resource"));
	}
}
----
====

Without any additional configuration, these tests create a stub with a request matcher
for the HTTP method and all headers except `host` and `content-length`. To match the
request more precisely (for example, to match the body of a POST or PUT), we need to
explicitly create a request matcher. Doing so has two effects:

* Creating a stub that matches only in the way you specify.
* Asserting that the request in the test case also matches the same conditions.

The main entry point for this feature is `WireMockRestDocs.verify()`, which can be used
as a substitute for the `document()` convenience method, as the following
example shows:

====
[source,java,indent=0]
----
import static org.springframework.cloud.contract.wiremock.restdocs.WireMockRestDocs.verify;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureRestDocs(outputDir = "target/snippets")
@AutoConfigureMockMvc
public class ApplicationTests {

	@Autowired
	private MockMvc mockMvc;

	@Test
	public void contextLoads() throws Exception {
		mockMvc.perform(post("/resource")
                .content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
				.andExpect(status().isOk())
				.andDo(verify().jsonPath("$.id"))
				.andDo(document("resource"));
	}
}
----
====

The preceding contract specifies that any valid POST with an `id` field receives the response
defined in this test. You can chain together calls to `.jsonPath()` to add additional
matchers. If JSON Path is unfamiliar, the https://github.com/jayway/JsonPath[JayWay
documentation] can help you get up to speed. The WebTestClient version of this test
has a similar `verify()` static helper that you insert in the same place.

Instead of the `jsonPath` and `contentType` convenience methods, you can also use the
WireMock APIs to verify that the request matches the created stub, as the
following example shows:

====
[source,java,indent=0]
----
	@Test
	public void contextLoads() throws Exception {
		mockMvc.perform(post("/resource")
                .content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
				.andExpect(status().isOk())
				.andDo(verify()
						.wiremock(WireMock.post(urlPathEquals("/resource"))
						.withRequestBody(matchingJsonPath("$.id"))
						.andDo(document("post-resource"))));
	}
----
====

The WireMock API is rich. You can match headers, query parameters, and the request body by
regex as well as by JSON path. You can use these features to create stubs with a wider
range of parameters. The preceding example generates a stub resembling the following example:

====
.post-resource.json
[source,json]
----
{
  "request" : {
    "url" : "/resource",
    "method" : "POST",
    "bodyPatterns" : [ {
      "matchesJsonPath" : "$.id"
    }]
  },
  "response" : {
    "status" : 200,
    "body" : "Hello World",
    "headers" : {
      "X-Application-Context" : "application:-1",
      "Content-Type" : "text/plain"
    }
  }
}
----
====

NOTE: You can use either the `wiremock()` method or the `jsonPath()` and `contentType()`
methods to create request matchers, but you cannot use both approaches.

On the consumer side, you can make the `resource.json` generated earlier in this section
available on the classpath (by
xref:../project-features-stubrunner/stub-runner-publishing-stubs-as-jars.adoc[Publishing Stubs as JARs], for example). After that, you can create a stub that uses WireMock in a
number of different ways, including by using
`@AutoConfigureWireMock(stubs="classpath:resource.json")`, as described earlier in this
document.

[[features-rest-docs-contracts]]
== Generating Contracts with REST Docs

You can also generate Spring Cloud Contract DSL files and documentation with Spring REST
Docs. If you do so in combination with Spring Cloud WireMock, you get both the contracts
and the stubs.

Why would you want to use this feature? Some people in the community asked questions
about a situation in which they would like to move to DSL-based contract definition,
but they already have a lot of Spring MVC tests. Using this feature lets you generate
the contract files that you can later modify and move to folders (defined in your
configuration) so that the plugin finds them.

NOTE: You might wonder why this functionality is in the WireMock module. The functionality
is there because it makes sense to generate both the contracts and the stubs.

Consider the following test:

====
[source,java]
----
include::{wiremock_tests}/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippetTests.java[tags=contract_snippet]
----
====

The preceding test creates the stub presented in the previous section, generating both
the contract and a documentation file.

The contract is called `index.groovy` and might resemble the following example:

====
[source,groovy]
----
import org.springframework.cloud.contract.spec.Contract

Contract.make {
    request {
        method 'POST'
        url '/foo'
        body('''
            {"foo": 23 }
        ''')
        headers {
            header('''Accept''', '''application/json''')
            header('''Content-Type''', '''application/json''')
        }
    }
    response {
        status OK()
        body('''
        bar
        ''')
        headers {
            header('''Content-Type''', '''application/json;charset=UTF-8''')
            header('''Content-Length''', '''3''')
        }
        bodyMatchers {
            jsonPath('$[?(@.foo >= 20)]', byType())
        }
    }
}
----
====

The generated document (formatted in Asciidoc in this case) contains a formatted
contract. The location of this file would be `index/dsl-contract.adoc`.

[[features-restdocs-priority-attribute]]
== Specifying the priority attribute

The method `SpringCloudContractRestDocs.dslContract()` takes an optional Map parameter that allows you to specify additional attributes in the template.

One of these attributes is the xref:project-features-contract/http.adoc#contract-dsl-http-top-level-elements[priority] field that you may specify as follows:

[source,java,indent=0]
----
SpringCloudContractRestDocs.dslContract(Map.of("priority", 1))
----

[[features-restdocs-override]]
== Overriding the DSL contract template

By default, the output of the contract is based on a file named `default-dsl-contract-only.snippet`.

You may provide a custom template file instead by overriding the getTemplate() method as follows:

[source,java,indent=0]
----
new ContractDslSnippet(){
    @Override
    protected String getTemplate() {
        return "custom-dsl-contract";
    }
}));
----

so the example above showing this line
[source,java,indent=0]
----
.andDo(document("index", SpringCloudContractRestDocs.dslContract()));
----

should be changed to:
[source,java,indent=0]
----
.andDo(document("index", new ContractDslSnippet(){
                            @Override
                            protected String getTemplate() {
                                return "custom-dsl-template";
                            }
                        }));
----

Templates are resolved by looking for resources on the classpath. The following locations are checked in order:

* `org/springframework/restdocs/templates/$\{templateFormatId}/$\{name}.snippet`
* `org/springframework/restdocs/templates/$\{name}.snippet`
* `org/springframework/restdocs/templates/$\{templateFormatId}/default-$\{name}.snippet`

Therefore in the example above you should place a file named custom-dsl-template.snippet in  `src/test/resources/org/springframework/restdocs/templates/custom-dsl-template.snippet`



