Add support for documenting body of a request, response or request part

Closes gh-318
Closes gh-319
This commit is contained in:
Andy Wilkinson
2016-10-31 12:46:36 +00:00
parent 1393182182
commit dec3727da1
31 changed files with 1160 additions and 95 deletions

View File

@@ -20,7 +20,7 @@ import org.springframework.restdocs.payload.FieldDescriptor;
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseBody;
public class Payload {
@@ -35,9 +35,7 @@ public class Payload {
public void customSubsectionId() {
// tag::custom-subsection-id[]
responseFields(beneathPath("weather.temperature").withSubsectionId("temp"),
fieldWithPath("high").description(""),
fieldWithPath("low").description(""));
responseBody(beneathPath("weather.temperature").withSubsectionId("temp"));
// end::custom-subsection-id[]
}

View File

@@ -26,9 +26,10 @@ import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuild
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseBody;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
import static org.springframework.restdocs.snippet.Attributes.attributes;
import static org.springframework.restdocs.snippet.Attributes.key;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -40,46 +41,50 @@ public class Payload {
public void response() throws Exception {
// tag::response[]
this.mockMvc.perform(get("/user/5").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("index", responseFields( // <1>
fieldWithPath("contact.email").description("The user's email address"), // <2>
fieldWithPath("contact.name").description("The user's name")))); // <3>
.andExpect(status().isOk())
.andDo(document("index",
responseFields( // <1>
fieldWithPath("contact.email")
.description("The user's email address"), // <2>
fieldWithPath("contact.name").description("The user's name")))); // <3>
// end::response[]
}
public void subsection() throws Exception {
// tag::subsection[]
this.mockMvc.perform(get("/user/5").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("index", responseFields( // <1>
subsectionWithPath("contact").description("The user's contact details")))); // <1>
.andExpect(status().isOk())
.andDo(document("index",
responseFields( // <1>
subsectionWithPath("contact")
.description("The user's contact details")))); // <1>
// end::subsection[]
}
public void explicitType() throws Exception {
this.mockMvc.perform(get("/user/5").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
// tag::explicit-type[]
.andDo(document("index", responseFields(
fieldWithPath("contact.email")
.type(JsonFieldType.STRING) // <1>
.description("The user's email address"))));
// end::explicit-type[]
.andExpect(status().isOk())
// tag::explicit-type[]
.andDo(document("index",
responseFields(
fieldWithPath("contact.email").type(JsonFieldType.STRING) // <1>
.description("The user's email address"))));
// end::explicit-type[]
}
public void constraints() throws Exception {
this.mockMvc.perform(post("/users/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
// tag::constraints[]
.andDo(document("create-user", requestFields(
attributes(key("title").value("Fields for user creation")), // <1>
fieldWithPath("name").description("The user's name")
.attributes(key("constraints")
.value("Must not be null. Must not be empty")), // <2>
fieldWithPath("email").description("The user's email address")
.attributes(key("constraints")
.value("Must be a valid email address"))))); // <3>
// end::constraints[]
.andExpect(status().isOk())
// tag::constraints[]
.andDo(document("create-user", requestFields(
attributes(key("title").value("Fields for user creation")), // <1>
fieldWithPath("name").description("The user's name")
.attributes(key("constraints")
.value("Must not be null. Must not be empty")), // <2>
fieldWithPath("email").description("The user's email address")
.attributes(key("constraints")
.value("Must be a valid email address"))))); // <3>
// end::constraints[]
}
public void descriptorReuse() throws Exception {
@@ -89,27 +94,39 @@ public class Payload {
// tag::single-book[]
this.mockMvc.perform(get("/books/1").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("book", responseFields(book))); // <1>
.andExpect(status().isOk()).andDo(document("book", responseFields(book))); // <1>
// end::single-book[]
// tag::book-array[]
this.mockMvc.perform(get("/books").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("book", responseFields(
fieldWithPath("[]").description("An array of books")) // <1>
.andWithPrefix("[].", book))); // <2>
.andDo(document("book",
responseFields(
fieldWithPath("[]").description("An array of books")) // <1>
.andWithPrefix("[].", book))); // <2>
// end::book-array[]
}
public void subsectionBeneathPath() throws Exception {
// tag::beneath-path[]
public void fieldsSubsection() throws Exception {
// tag::fields-subsection[]
this.mockMvc.perform(get("/locations/1").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("location", responseFields(beneathPath("weather.temperature"), // <1>
fieldWithPath("high").description("The forecast high in degrees celcius"), // <2>
fieldWithPath("low").description("The forecast low in degrees celcius"))));
// end::beneath-path[]
.andDo(document("location",
responseFields(beneathPath("weather.temperature"), // <1>
fieldWithPath("high").description(
"The forecast high in degrees celcius"), // <2>
fieldWithPath("low")
.description("The forecast low in degrees celcius"))));
// end::fields-subsection[]
}
public void bodySubsection() throws Exception {
// tag::body-subsection[]
this.mockMvc.perform(get("/locations/1").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andDo(document("location",
responseBody(beneathPath("weather.temperature")))); // <1>
// end::body-subsection[]
}
}

View File

@@ -23,6 +23,7 @@ import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.fileUpload;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestPartBody;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestPartFields;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -30,8 +31,8 @@ public class RequestPartPayload {
private MockMvc mockMvc;
public void response() throws Exception {
// tag::payload[]
public void fields() throws Exception {
// tag::fields[]
MockMultipartFile image = new MockMultipartFile("image", "image.png", "image/png",
"<<png data>>".getBytes());
MockMultipartFile metadata = new MockMultipartFile("metadata", "",
@@ -42,7 +43,21 @@ public class RequestPartPayload {
.andExpect(status().isOk())
.andDo(document("image-upload", requestPartFields("metadata", // <1>
fieldWithPath("version").description("The version of the image")))); // <2>
// end::payload[]
// end::fields[]
}
public void body() throws Exception {
// tag::body[]
MockMultipartFile image = new MockMultipartFile("image", "image.png", "image/png",
"<<png data>>".getBytes());
MockMultipartFile metadata = new MockMultipartFile("metadata", "",
"application/json", "{ \"version\": \"1.0\"}".getBytes());
this.mockMvc.perform(fileUpload("/images").file(image).file(metadata)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(document("image-upload", requestPartBody("metadata"))); // <1>
// end::body[]
}
}

View File

@@ -26,6 +26,7 @@ import static org.hamcrest.CoreMatchers.is;
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseBody;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
@@ -46,7 +47,7 @@ public class Payload {
.then().assertThat().statusCode(is(200));
// end::response[]
}
public void subsection() throws Exception {
// tag::subsection[]
RestAssured.given(this.spec).accept("application/json")
@@ -107,15 +108,24 @@ public class Payload {
// end::book-array[]
}
public void subsectionBeneathPath() throws Exception {
// tag::beneath-path[]
public void fieldsSubsection() throws Exception {
// tag::fields-subsection[]
RestAssured.given(this.spec).accept("application/json")
.filter(document("location", responseFields(beneathPath("weather.temperature"), // <1>
fieldWithPath("high").description("The forecast high in degrees celcius"), // <2>
fieldWithPath("low").description("The forecast low in degrees celcius"))))
.when().get("/locations/1")
.then().assertThat().statusCode(is(200));
// end::beneath-path[]
// end::fields-subsection[]
}
public void bodySubsection() throws Exception {
// tag::body-subsection[]
RestAssured.given(this.spec).accept("application/json")
.filter(document("location", responseBody(beneathPath("weather.temperature")))) // <1>
.when().get("/locations/1")
.then().assertThat().statusCode(is(200));
// end::body-subsection[]
}
}

View File

@@ -25,6 +25,7 @@ import com.jayway.restassured.specification.RequestSpecification;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestPartBody;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestPartFields;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
@@ -32,8 +33,8 @@ public class RequestPartPayload {
private RequestSpecification spec;
public void response() throws Exception {
// tag::payload[]
public void fields() throws Exception {
// tag::fields[]
Map<String, String> metadata = new HashMap<>();
metadata.put("version", "1.0");
RestAssured.given(this.spec).accept("application/json")
@@ -42,7 +43,19 @@ public class RequestPartPayload {
.when().multiPart("image", new File("image.png"), "image/png")
.multiPart("metadata", metadata).post("images")
.then().assertThat().statusCode(is(200));
// end::payload[]
// end::fields[]
}
public void body() throws Exception {
// tag::body[]
Map<String, String> metadata = new HashMap<>();
metadata.put("version", "1.0");
RestAssured.given(this.spec).accept("application/json")
.filter(document("image-upload", requestPartBody("metadata"))) // <1>
.when().multiPart("image", new File("image.png"), "image/png")
.multiPart("metadata", metadata).post("images")
.then().assertThat().statusCode(is(200));
// end::body[]
}
}