Spring RestDocs can be
used to generate documentation (e.g. in asciidoctor format) for an
HTTP API with Spring MockMvc or Rest Assured. At the same time as you
generate documentation for your API, you can also generate WireMock
stubs, by using Spring Cloud Contract WireMock. Just write your normal
RestDocs test cases and use @AutoConfigureRestDocs to have stubs
automatically in the restdocs output directory. For example:
@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")); } }
From this test will be generated a WireMock stub at "target/snippets/stubs/resource.json". It matches all GET requests to the "/resource" path.
Without any additional configuration this will 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. This will do two things: 1) create a stub that only matches the way you specify, 2) assert that the request in the test case also matches the same conditions.
The main entry point for this is WireMockRestDocs.verify() which can
be used as a substitute for the document() convenience method. For
example:
@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") .stub("resource")); } }
So this contract is saying: any valid POST with an "id" field will get
back an the same response as in this test. You can chain together
calls to .jsonPath() to add additional matchers. The
JayWay documentation can help you
to get up to speed with JSON Path if it is unfamiliar to you.
Instead of the jsonPath and contentType convenience methods, you
can also use the WireMock APIs to verify the request matches the
created stub. Example:
@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")) .stub("post-resource")); }
The WireMock API is rich - you can match headers, query parameters, and request body by regex as well as by json path - so this can useful to create stubs with a wider range of parameters. The above example will generate a stub something like this:
post-resource.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 |
On the consumer side, you can make the resource.json generated above
available on the classpath (by publishing stubs as JARs for example).
After that, you can create a stub using WireMock in a
number of different ways, including as described above using
@AutoConfigureWireMock(stubs="classpath:resource.json").