Improve support for documenting fields in req and resp payloads
This commit improves the support for documenting the fields found in request and response payloads. The improvements include: - Using the term "payload" rather than "state" as the latter is somewhat HAL-specific - Code simplification, including the removal of the Path abstraction - Automatically determining the type of a field based on the payload that's being tested - Updating the samples to use the new API In addition to these improvements, support for documenting field constraints has been removed as more thought is required. The FieldDescriptor abstraction is used to describe both request and response fields, however it's not clear that contraints apply to both and they certainly don't apply in the same way. For the time being at least, users who want to document a field's constraints can do so as part of its description. Closes gh-24
This commit is contained in:
@@ -20,6 +20,7 @@ import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.springframework.restdocs.RestDocumentation.document;
|
||||
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
@@ -40,6 +41,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.restdocs.config.RestDocumentationConfigurer;
|
||||
import org.springframework.restdocs.payload.FieldType;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
@@ -87,20 +89,26 @@ public class ApiDocumentation {
|
||||
.andExpect(jsonPath("timestamp", is(notNullValue())))
|
||||
.andExpect(jsonPath("status", is(400)))
|
||||
.andExpect(jsonPath("path", is(notNullValue())))
|
||||
.andDo(document("error-example"));
|
||||
.andDo(document("error-example")
|
||||
.withResponseFields(
|
||||
fieldWithPath("error").description("The HTTP error that occurred, e.g. `Bad Request`"),
|
||||
fieldWithPath("message").description("A description of the cause of the error"),
|
||||
fieldWithPath("path").description("The path to which the request was made"),
|
||||
fieldWithPath("status").description("The HTTP status code, e.g. `400`"),
|
||||
fieldWithPath("timestamp").description("The time, in milliseconds, at which the error occurred")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void indexExample() throws Exception {
|
||||
this.mockMvc.perform(get("/"))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document("index-example").withLinks(
|
||||
linkWithRel("notes").description(
|
||||
"The <<resources-notes,Notes resource>>"),
|
||||
linkWithRel("tags").description(
|
||||
"The <<resources-tags,Tags resource>>"),
|
||||
linkWithRel("profile").description(
|
||||
"The ALPS profile for the service")));
|
||||
.andDo(document("index-example")
|
||||
.withLinks(
|
||||
linkWithRel("notes").description("The <<resources-notes,Notes resource>>"),
|
||||
linkWithRel("tags").description("The <<resources-tags,Tags resource>>"),
|
||||
linkWithRel("profile").description("The ALPS profile for the service"))
|
||||
.withResponseFields(
|
||||
fieldWithPath("_links").description("<<resources-index-links,Links>> to other resources")));
|
||||
|
||||
}
|
||||
|
||||
@@ -116,7 +124,9 @@ public class ApiDocumentation {
|
||||
|
||||
this.mockMvc.perform(get("/notes"))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document("notes-list-example"));
|
||||
.andDo(document("notes-list-example")
|
||||
.withResponseFields(
|
||||
fieldWithPath("_embedded.notes").description("An array of <<resources-note, Note resources>>")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -140,7 +150,11 @@ public class ApiDocumentation {
|
||||
post("/notes").contentType(MediaTypes.HAL_JSON).content(
|
||||
this.objectMapper.writeValueAsString(note))).andExpect(
|
||||
status().isCreated())
|
||||
.andDo(document("notes-create-example"));
|
||||
.andDo(document("notes-create-example")
|
||||
.withRequestFields(
|
||||
fieldWithPath("title").description("The title of the note"),
|
||||
fieldWithPath("body").description("The body of the note"),
|
||||
fieldWithPath("tags").description("An array of tag resource URIs")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -176,9 +190,11 @@ public class ApiDocumentation {
|
||||
.andDo(document("note-get-example")
|
||||
.withLinks(
|
||||
linkWithRel("self").description("This <<resources-note,note>>"),
|
||||
linkWithRel("tags").description(
|
||||
"This note's <<resources-note-tags,tags>>")));
|
||||
|
||||
linkWithRel("tags").description("This note's tags"))
|
||||
.withResponseFields(
|
||||
fieldWithPath("title").description("The title of the note"),
|
||||
fieldWithPath("body").description("The body of the note"),
|
||||
fieldWithPath("_links").description("<<resources-note-links,Links>> to other resources")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -192,7 +208,9 @@ public class ApiDocumentation {
|
||||
|
||||
this.mockMvc.perform(get("/tags"))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document("tags-list-example"));
|
||||
.andDo(document("tags-list-example")
|
||||
.withResponseFields(
|
||||
fieldWithPath("_embedded.tags").description("An array of <<resources-tag,Tag resources>>")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -202,9 +220,11 @@ public class ApiDocumentation {
|
||||
|
||||
this.mockMvc.perform(
|
||||
post("/tags").contentType(MediaTypes.HAL_JSON).content(
|
||||
this.objectMapper.writeValueAsString(tag))).andExpect(
|
||||
status().isCreated())
|
||||
.andDo(document("tags-create-example"));
|
||||
this.objectMapper.writeValueAsString(tag)))
|
||||
.andExpect(status().isCreated())
|
||||
.andDo(document("tags-create-example")
|
||||
.withRequestFields(
|
||||
fieldWithPath("name").description("The name of the tag")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -243,7 +263,12 @@ public class ApiDocumentation {
|
||||
patch(noteLocation).contentType(MediaTypes.HAL_JSON).content(
|
||||
this.objectMapper.writeValueAsString(noteUpdate)))
|
||||
.andExpect(status().isNoContent())
|
||||
.andDo(document("note-update-example"));
|
||||
.andDo(document("note-update-example")
|
||||
.withRequestFields(
|
||||
fieldWithPath("title").description("The title of the note").type(FieldType.STRING).optional(),
|
||||
fieldWithPath("body").description("The body of the note").type(FieldType.STRING).optional(),
|
||||
fieldWithPath("tags").description("An array of tag resource URIs").optional()));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -261,11 +286,13 @@ public class ApiDocumentation {
|
||||
this.mockMvc.perform(get(tagLocation))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("name", is(tag.get("name"))))
|
||||
.andDo(document("tag-get-example").withLinks(
|
||||
linkWithRel("self").description("This <<resources-tag,tag>>"),
|
||||
linkWithRel("notes")
|
||||
.description(
|
||||
"The <<resources-tagged-notes,notes>> that have this tag")));
|
||||
.andDo(document("tag-get-example")
|
||||
.withLinks(
|
||||
linkWithRel("self").description("This <<resources-tag,tag>>"),
|
||||
linkWithRel("notes").description("The <<resources-tagged-notes,notes>> that have this tag"))
|
||||
.withResponseFields(
|
||||
fieldWithPath("name").description("The name of the tag"),
|
||||
fieldWithPath("_links").description("<<resources-tag-links,Links>> to other resources")));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -287,7 +314,9 @@ public class ApiDocumentation {
|
||||
patch(tagLocation).contentType(MediaTypes.HAL_JSON).content(
|
||||
this.objectMapper.writeValueAsString(tagUpdate)))
|
||||
.andExpect(status().isNoContent())
|
||||
.andDo(document("tag-update-example"));
|
||||
.andDo(document("tag-update-example")
|
||||
.withRequestFields(
|
||||
fieldWithPath("name").description("The name of the tag")));
|
||||
}
|
||||
|
||||
private void createNote(String title, String body) {
|
||||
|
||||
Reference in New Issue
Block a user