modelForContract = new HashMap<>();
+ insertRequestModel(operation, modelForContract);
+ insertResponseModel(operation, modelForContract);
+ return modelForContract;
+ }
+
+ private void storeDslContract(Operation operation, String content)
+ throws IOException {
+ RestDocumentationContext context = (RestDocumentationContext) operation
+ .getAttributes().get(RestDocumentationContext.class.getName());
+ File output = new File(context.getOutputDirectory(),
+ CONTRACTS_FOLDER + "/" + operation.getName() + ".groovy");
+ output.getParentFile().mkdirs();
+ try (Writer writer = new OutputStreamWriter(new FileOutputStream(output))) {
+ writer.append(content);
+ }
+ }
+}
+
+class JsonPaths {
+ private final String jsonPath;
+
+ JsonPaths(String jsonPath) {
+ this.jsonPath = jsonPath;
+ }
+
+ public String getJsonPath() {
+ return this.jsonPath;
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/SpringCloudContractRestDocs.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/SpringCloudContractRestDocs.java
new file mode 100644
index 0000000000..d638e6d74f
--- /dev/null
+++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/SpringCloudContractRestDocs.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2012-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.contract.wiremock.restdocs;
+
+import java.util.Map;
+
+import org.springframework.restdocs.snippet.Snippet;
+
+/**
+ * Convenience class for setting up RestDocs to generate a {@link org.springframework.restdocs.snippet.Snippet}
+ * with Spring Cloud Contract DSL. Example usage:
+ *
+ *
+ * @RunWith(SpringRunner.class)
+ * @SpringBootTest
+ * @AutoConfigureRestDocs(outputDir = "target/snippets")
+ * @AutoConfigureMockMvc
+ * public class ContractRestDocsApplicationTests {
+ *
+ * @Autowired
+ * private MockMvc mockMvc;
+ *
+ * @Test
+ * public void contextLoads() throws Exception {
+ * this.mockMvc.perform(post("/foo")
+ * .accept(MediaType.APPLICATION_PDF)
+ * .accept(MediaType.APPLICATION_JSON)
+ * .contentType(MediaType.APPLICATION_JSON)
+ * .content("{\"foo\": 23 }"))
+ * .andExpect(status().isOk())
+ * .andExpect(content().string("bar"))
+ * // first WireMock
+ * .andDo(WireMockRestDocs.verify()
+ * .jsonPath("$[?(@.foo >= 20)]")
+ * .contentType(MediaType.valueOf("application/json"))
+ * .stub("shouldGrantABeerIfOldEnough"))
+ * // then Contract DSL documentation
+ * .andDo(document("index", SpringCloudContractRestDocs.dslContract()));
+ * }
+ *
+ *
+ * which creates a file "target/snippets/contracts/index.groovy" and a
+ * standard documentation entitled `dsl-contract.adoc` containing that contract.
+ *
+ * @author Marcin Grzejszczak
+ * @since 1.0.4
+ */
+public class SpringCloudContractRestDocs {
+
+ private SpringCloudContractRestDocs() {
+
+ }
+
+ /**
+ * Returns a new {@code Snippet} that will document Spring Cloud Contract DSL for the API
+ * operation.
+ *
+ * @return the snippet that will document the Spring Cloud Contract DSL
+ */
+ public static Snippet dslContract() {
+ return new ContractDslSnippet();
+ }
+
+ /**
+ * Returns a new {@code Snippet} that will document the Spring Cloud Contract DSL for the API
+ * operation. The given {@code attributes} will be available during snippet
+ * generation.
+ *
+ * @param attributes the attributes
+ * @return the snippet that will document the Spring Cloud Contract DSL
+ */
+ public static Snippet dslContract(Map attributes) {
+ return new ContractDslSnippet(attributes);
+ }
+
+}
diff --git a/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/asciidoctor/default-dsl-contract.snippet b/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/asciidoctor/default-dsl-contract.snippet
new file mode 100644
index 0000000000..200deae6cc
--- /dev/null
+++ b/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/asciidoctor/default-dsl-contract.snippet
@@ -0,0 +1,4 @@
+[source,groovy]
+----
+{{contract}}
+----
\ No newline at end of file
diff --git a/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/default-dsl-contract-only.snippet b/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/default-dsl-contract-only.snippet
new file mode 100644
index 0000000000..96dacddc37
--- /dev/null
+++ b/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/default-dsl-contract-only.snippet
@@ -0,0 +1,42 @@
+import org.springframework.cloud.contract.spec.Contract
+
+Contract.make {
+ request {
+ method '{{request_method}}'
+ url '{{request_url}}'
+ {{#request_body_present}}
+ body('''
+ {{request_body}}
+ ''')
+ {{/request_body_present}}
+ {{#request_headers_present}}
+ headers {
+ {{#request_headers}}
+ header('''{{key}}''', '''{{value}}''')
+ {{/request_headers}}
+ }
+ {{/request_headers_present}}
+ }
+ response {
+ status {{response_status}}
+ {{#response_body_present}}
+ body('''
+ {{response_body}}
+ ''')
+ {{/response_body_present}}
+ {{#response_headers_present}}
+ headers {
+ {{#response_headers}}
+ header('''{{key}}''', '''{{value}}''')
+ {{/response_headers}}
+ }
+ {{/response_headers_present}}
+ {{#response_json_paths_present}}
+ testMatchers {
+ {{#response_json_paths}}
+ jsonPath('{{jsonPath}}', byType())
+ {{/response_json_paths}}
+ }
+ {{/response_json_paths_present}}
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/markdown/default-dsl-contract.snippet b/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/markdown/default-dsl-contract.snippet
new file mode 100644
index 0000000000..8e538e30eb
--- /dev/null
+++ b/spring-cloud-contract-wiremock/src/main/resources/org/springframework/restdocs/templates/markdown/default-dsl-contract.snippet
@@ -0,0 +1,3 @@
+```groovy
+{{contract}}
+```
\ No newline at end of file
diff --git a/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippetTests.java b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippetTests.java
new file mode 100644
index 0000000000..f38b1d38dc
--- /dev/null
+++ b/spring-cloud-contract-wiremock/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippetTests.java
@@ -0,0 +1,137 @@
+package org.springframework.cloud.contract.wiremock.restdocs;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.cloud.contract.spec.Contract;
+import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.MediaType;
+import org.springframework.restdocs.JUnitRestDocumentation;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.context.WebApplicationContext;
+
+import static org.assertj.core.api.BDDAssertions.then;
+import static org.springframework.cloud.contract.wiremock.restdocs.SpringCloudContractRestDocs.dslContract;
+import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
+import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+/**
+ * @author Marcin Grzejszczak
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = ContractDslSnippetTests.Config.class)
+public class ContractDslSnippetTests {
+
+ private static final String OUTPUT = "target/generated-snippets";
+ @Rule
+ public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation(OUTPUT);
+
+ MockMvc mockMvc;
+ @Autowired WebApplicationContext context;
+
+ @Before
+ public void setUp() {
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
+ .apply(documentationConfiguration(this.restDocumentation))
+ .build();
+ }
+
+ @Test
+ public void should_create_contract_template_and_doc() throws Exception {
+ //tag::contract_snippet[]
+ this.mockMvc.perform(post("/foo")
+ .accept(MediaType.APPLICATION_PDF)
+ .accept(MediaType.APPLICATION_JSON)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content("{\"foo\": 23 }"))
+ .andExpect(status().isOk())
+ .andExpect(content().string("bar"))
+ // first WireMock
+ .andDo(WireMockRestDocs.verify()
+ .jsonPath("$[?(@.foo >= 20)]")
+ .contentType(MediaType.valueOf("application/json"))
+ .stub("shouldGrantABeerIfOldEnough"))
+ // then Contract DSL documentation
+ .andDo(document("index", SpringCloudContractRestDocs.dslContract()));
+ //end::contract_snippet[]
+
+ then(file("/contracts/index.groovy")).exists();
+ then(file("/index/dsl-contract.adoc")).exists();
+ String contract = readFromFile(file("/contracts/index.groovy"));
+ // try to parse the contract
+ Contract parsedContract = ContractVerifierDslConverter.convert(contract);
+ then(parsedContract.getRequest().getHeaders().getEntries()).isNotEmpty();
+ then(parsedContract.getRequest().getMethod().getClientValue()).isNotNull();
+ then(parsedContract.getRequest().getUrl().getClientValue()).isNotNull();
+ then(parsedContract.getRequest().getBody().getClientValue()).isNotNull();
+ then(parsedContract.getResponse().getStatus().getClientValue()).isNotNull();
+ then(parsedContract.getResponse().getHeaders().getEntries()).isNotEmpty();
+ then(parsedContract.getResponse().getBody().getClientValue()).isNotNull();
+ then(parsedContract.getResponse().getMatchers().hasMatchers()).isTrue();
+ }
+
+ @Test
+ public void should_create_contract_template_and_doc_without_body_and_headers() throws Exception {
+ this.mockMvc.perform(MockMvcRequestBuilders.get("/foo"))
+ .andExpect(status().isOk())
+ .andDo(document("empty", dslContract()));
+
+ then(file("/contracts/empty.groovy")).exists();
+ then(file("/empty/dsl-contract.adoc")).exists();
+ String contract = readFromFile(file("/contracts/empty.groovy"));
+ // try to parse the contract
+ Contract parsedContract = ContractVerifierDslConverter.convert(contract);
+ then(parsedContract.getRequest().getHeaders().getEntries()).isNotEmpty();
+ then(parsedContract.getRequest().getMethod().getClientValue()).isNotNull();
+ then(parsedContract.getRequest().getUrl().getClientValue()).isNotNull();
+ then(parsedContract.getRequest().getBody()).isNull();
+ then(parsedContract.getResponse().getStatus().getClientValue()).isNotNull();
+ then(parsedContract.getResponse().getHeaders()).isNull();
+ then(parsedContract.getResponse().getBody()).isNull();
+ then(parsedContract.getResponse().getMatchers()).isNull();
+ }
+
+ private File file(String name) throws URISyntaxException {
+ return new File(OUTPUT, name);
+ }
+
+ private String readFromFile(File f) throws IOException {
+ byte[] encoded = Files.readAllBytes(f.toPath());
+ return new String(encoded, StandardCharsets.UTF_8);
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ @RestController
+ static class Config {
+
+ @PostMapping("/foo")
+ String foo() {
+ return "bar";
+ }
+
+ @GetMapping("/foo")
+ void getFoo() {
+ }
+ }
+}
\ No newline at end of file