From 26ff2ec8a51421e15acf032bd7f19968ca1697a7 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 25 May 2016 12:02:53 +0100 Subject: [PATCH] Update HATEOAS sample to use new API for generating extra snippets See gh-249 --- .../com/example/notes/ApiDocumentation.java | 300 +++++++++--------- 1 file changed, 149 insertions(+), 151 deletions(-) diff --git a/samples/rest-notes-spring-hateoas/src/test/java/com/example/notes/ApiDocumentation.java b/samples/rest-notes-spring-hateoas/src/test/java/com/example/notes/ApiDocumentation.java index 90abbdc6..b3cbb58f 100644 --- a/samples/rest-notes-spring-hateoas/src/test/java/com/example/notes/ApiDocumentation.java +++ b/samples/rest-notes-spring-hateoas/src/test/java/com/example/notes/ApiDocumentation.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2015 the original author or authors. + * Copyright 2014-2016 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. @@ -34,7 +34,6 @@ import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWit import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.restdocs.snippet.Attributes.key; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -73,7 +72,7 @@ public class ApiDocumentation { @Rule public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("build/generated-snippets"); - private RestDocumentationResultHandler document; + private RestDocumentationResultHandler documentationHandler; @Autowired private NoteRepository noteRepository; @@ -91,77 +90,73 @@ public class ApiDocumentation { @Before public void setUp() { - this.document = document("{method-name}", - preprocessRequest(prettyPrint()), - preprocessResponse(prettyPrint())); + this.documentationHandler = document("{method-name}", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint())); this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) - .apply(documentationConfiguration(this.restDocumentation)) - .alwaysDo(this.document) - .build(); + .apply(documentationConfiguration(this.restDocumentation)) + .alwaysDo(this.documentationHandler) + .build(); } @Test public void headersExample() throws Exception { - this.document.snippets(responseHeaders( - headerWithName("Content-Type").description("The Content-Type of the payload, e.g. `application/hal+json`"))); - - this.mockMvc.perform(get("/")) - .andExpect(status().isOk()); + this.mockMvc + .perform(get("/")) + .andExpect(status().isOk()) + .andDo(this.documentationHandler.document( + responseHeaders( + headerWithName("Content-Type").description("The Content-Type of the payload, e.g. `application/hal+json`")))); } @Test public void errorExample() throws Exception { - this.document.snippets(responseFields( - 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"))); - this.mockMvc .perform(get("/error") - .requestAttr(RequestDispatcher.ERROR_STATUS_CODE, 400) - .requestAttr(RequestDispatcher.ERROR_REQUEST_URI, - "/notes") - .requestAttr(RequestDispatcher.ERROR_MESSAGE, - "The tag 'http://localhost:8080/tags/123' does not exist")) - .andDo(print()).andExpect(status().isBadRequest()) + .requestAttr(RequestDispatcher.ERROR_STATUS_CODE, 400) + .requestAttr(RequestDispatcher.ERROR_REQUEST_URI, "/notes") + .requestAttr(RequestDispatcher.ERROR_MESSAGE, "The tag 'http://localhost:8080/tags/123' does not exist")) + .andExpect(status().isBadRequest()) .andExpect(jsonPath("error", is("Bad Request"))) .andExpect(jsonPath("timestamp", is(notNullValue()))) .andExpect(jsonPath("status", is(400))) - .andExpect(jsonPath("path", is(notNullValue()))); + .andExpect(jsonPath("path", is(notNullValue()))) + .andDo(this.documentationHandler.document( + responseFields( + 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.document.snippets( - links( - linkWithRel("notes").description("The <>"), - linkWithRel("tags").description("The <>")), - responseFields( - fieldWithPath("_links").description("<> to other resources"))); - this.mockMvc.perform(get("/")) - .andExpect(status().isOk()); + .andExpect(status().isOk()) + .andDo(this.documentationHandler.document( + links( + linkWithRel("notes").description("The <>"), + linkWithRel("tags").description("The <>")), + responseFields( + fieldWithPath("_links").description("<> to other resources")))); } @Test public void notesListExample() throws Exception { this.noteRepository.deleteAll(); - createNote("REST maturity model", - "http://martinfowler.com/articles/richardsonMaturityModel.html"); - createNote("Hypertext Application Language (HAL)", - "http://stateless.co/hal_specification.html"); + createNote("REST maturity model", "http://martinfowler.com/articles/richardsonMaturityModel.html"); + createNote("Hypertext Application Language (HAL)", "http://stateless.co/hal_specification.html"); createNote("Application-Level Profile Semantics (ALPS)", "http://alps.io/spec/"); - this.document.snippets( + this.mockMvc + .perform(get("/notes")) + .andExpect(status().isOk()) + .andDo(this.documentationHandler.document( responseFields( - fieldWithPath("_embedded.notes").description("An array of <>"))); - - this.mockMvc.perform(get("/notes")) - .andExpect(status().isOk()); + fieldWithPath("_embedded.notes").description("An array of <>")))); } @Test @@ -170,11 +165,11 @@ public class ApiDocumentation { tag.put("name", "REST"); String tagLocation = this.mockMvc - .perform( - post("/tags").contentType(MediaTypes.HAL_JSON).content( - this.objectMapper.writeValueAsString(tag))) - .andExpect(status().isCreated()).andReturn().getResponse() - .getHeader("Location"); + .perform(post("/tags") + .contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(tag))) + .andExpect(status().isCreated()) + .andReturn().getResponse().getHeader("Location"); Map note = new HashMap(); note.put("title", "REST maturity model"); @@ -183,16 +178,17 @@ public class ApiDocumentation { ConstrainedFields fields = new ConstrainedFields(NoteInput.class); - this.document.snippets( + this.mockMvc + .perform(post("/notes") + .contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(note))) + .andExpect( + status().isCreated()) + .andDo(this.documentationHandler.document( requestFields( - fields.withPath("title").description("The title of the note"), - fields.withPath("body").description("The body of the note"), - fields.withPath("tags").description("An array of tag resource URIs"))); - - this.mockMvc.perform( - post("/notes").contentType(MediaTypes.HAL_JSON).content( - this.objectMapper.writeValueAsString(note))) - .andExpect(status().isCreated()); + fields.withPath("title").description("The title of the note"), + fields.withPath("body").description("The body of the note"), + fields.withPath("tags").description("An array of tag resource URIs")))); } @Test @@ -201,11 +197,11 @@ public class ApiDocumentation { tag.put("name", "REST"); String tagLocation = this.mockMvc - .perform( - post("/tags").contentType(MediaTypes.HAL_JSON).content( - this.objectMapper.writeValueAsString(tag))) - .andExpect(status().isCreated()).andReturn().getResponse() - .getHeader("Location"); + .perform(post("/tags") + .contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(tag))) + .andExpect(status().isCreated()) + .andReturn().getResponse().getHeader("Location"); Map note = new HashMap(); note.put("title", "REST maturity model"); @@ -213,27 +209,27 @@ public class ApiDocumentation { note.put("tags", Arrays.asList(tagLocation)); String noteLocation = this.mockMvc - .perform( - post("/notes").contentType(MediaTypes.HAL_JSON).content( - this.objectMapper.writeValueAsString(note))) - .andExpect(status().isCreated()).andReturn().getResponse() - .getHeader("Location"); + .perform(post("/notes") + .contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(note))) + .andExpect(status().isCreated()) + .andReturn().getResponse().getHeader("Location"); - this.document.snippets( - links( - linkWithRel("self").description("This <>"), - linkWithRel("note-tags").description("This note's <>")), - responseFields( - fieldWithPath("title").description("The title of the note"), - fieldWithPath("body").description("The body of the note"), - fieldWithPath("_links").description("<> to other resources"))); - - this.mockMvc.perform(get(noteLocation)) + this.mockMvc + .perform(get(noteLocation)) .andExpect(status().isOk()) .andExpect(jsonPath("title", is(note.get("title")))) .andExpect(jsonPath("body", is(note.get("body")))) .andExpect(jsonPath("_links.self.href", is(noteLocation))) - .andExpect(jsonPath("_links.note-tags", is(notNullValue()))); + .andExpect(jsonPath("_links.note-tags", is(notNullValue()))) + .andDo(this.documentationHandler.document( + links( + linkWithRel("self").description("This <>"), + linkWithRel("note-tags").description("This note's <>")), + responseFields( + fieldWithPath("title").description("The title of the note"), + fieldWithPath("body").description("The body of the note"), + fieldWithPath("_links").description("<> to other resources")))); } @@ -246,12 +242,12 @@ public class ApiDocumentation { createTag("Hypermedia"); createTag("HTTP"); - this.document.snippets( + this.mockMvc + .perform(get("/tags")) + .andExpect(status().isOk()) + .andDo(this.documentationHandler.document( responseFields( - fieldWithPath("_embedded.tags").description("An array of <>"))); - - this.mockMvc.perform(get("/tags")) - .andExpect(status().isOk()); + fieldWithPath("_embedded.tags").description("An array of <>")))); } @Test @@ -261,14 +257,14 @@ public class ApiDocumentation { ConstrainedFields fields = new ConstrainedFields(TagInput.class); - this.document.snippets( + this.mockMvc + .perform(post("/tags") + .contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(tag))) + .andExpect(status().isCreated()) + .andDo(this.documentationHandler.document( requestFields( - fields.withPath("name").description("The name of the tag"))); - - this.mockMvc.perform( - post("/tags").contentType(MediaTypes.HAL_JSON).content( - this.objectMapper.writeValueAsString(tag))) - .andExpect(status().isCreated()); + fields.withPath("name").description("The name of the tag")))); } @Test @@ -278,50 +274,52 @@ public class ApiDocumentation { note.put("body", "http://martinfowler.com/articles/richardsonMaturityModel.html"); String noteLocation = this.mockMvc - .perform( - post("/notes").contentType(MediaTypes.HAL_JSON).content( - this.objectMapper.writeValueAsString(note))) - .andExpect(status().isCreated()).andReturn().getResponse() - .getHeader("Location"); + .perform(post("/notes") + .contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(note))) + .andExpect(status().isCreated()) + .andReturn().getResponse().getHeader("Location"); - this.mockMvc.perform(get(noteLocation)).andExpect(status().isOk()) - .andExpect(jsonPath("title", is(note.get("title")))) - .andExpect(jsonPath("body", is(note.get("body")))) - .andExpect(jsonPath("_links.self.href", is(noteLocation))) - .andExpect(jsonPath("_links.note-tags", is(notNullValue()))); + this.mockMvc + .perform(get(noteLocation)) + .andExpect(status().isOk()) + .andExpect(jsonPath("title", is(note.get("title")))) + .andExpect(jsonPath("body", is(note.get("body")))) + .andExpect(jsonPath("_links.self.href", is(noteLocation))) + .andExpect(jsonPath("_links.note-tags", is(notNullValue()))); Map tag = new HashMap(); tag.put("name", "REST"); String tagLocation = this.mockMvc - .perform( - post("/tags").contentType(MediaTypes.HAL_JSON).content( - this.objectMapper.writeValueAsString(tag))) - .andExpect(status().isCreated()).andReturn().getResponse() - .getHeader("Location"); + .perform(post("/tags") + .contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(tag))) + .andExpect(status().isCreated()) + .andReturn().getResponse().getHeader("Location"); Map noteUpdate = new HashMap(); noteUpdate.put("tags", Arrays.asList(tagLocation)); ConstrainedFields fields = new ConstrainedFields(NotePatchInput.class); - - this.document.snippets( - requestFields( - fields.withPath("title") - .description("The title of the note") - .type(JsonFieldType.STRING) - .optional(), - fields.withPath("body") - .description("The body of the note") - .type(JsonFieldType.STRING) - .optional(), - fields.withPath("tags") - .description("An array of tag resource URIs"))); - this.mockMvc.perform( - patch(noteLocation).contentType(MediaTypes.HAL_JSON).content( - this.objectMapper.writeValueAsString(noteUpdate))) - .andExpect(status().isNoContent()); + this.mockMvc + .perform(patch(noteLocation) + .contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(noteUpdate))) + .andExpect(status().isNoContent()) + .andDo(this.documentationHandler.document( + requestFields( + fields.withPath("title") + .description("The title of the note") + .type(JsonFieldType.STRING) + .optional(), + fields.withPath("body") + .description("The body of the note") + .type(JsonFieldType.STRING) + .optional(), + fields.withPath("tags") + .description("An array of tag resource URIs")))); } @Test @@ -330,23 +328,23 @@ public class ApiDocumentation { tag.put("name", "REST"); String tagLocation = this.mockMvc - .perform( - post("/tags").contentType(MediaTypes.HAL_JSON).content( - this.objectMapper.writeValueAsString(tag))) - .andExpect(status().isCreated()).andReturn().getResponse() - .getHeader("Location"); - - this.document.snippets( - links( - linkWithRel("self").description("This <>"), - linkWithRel("tagged-notes").description("The <> that have this tag")), - responseFields( - fieldWithPath("name").description("The name of the tag"), - fieldWithPath("_links").description("<> to other resources"))); + .perform(post("/tags") + .contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(tag))) + .andExpect(status().isCreated()) + .andReturn().getResponse().getHeader("Location"); - this.mockMvc.perform(get(tagLocation)) + this.mockMvc + .perform(get(tagLocation)) .andExpect(status().isOk()) - .andExpect(jsonPath("name", is(tag.get("name")))); + .andExpect(jsonPath("name", is(tag.get("name")))) + .andDo(this.documentationHandler.document( + links( + linkWithRel("self").description("This <>"), + linkWithRel("tagged-notes").description("The <> that have this tag")), + responseFields( + fieldWithPath("name").description("The name of the tag"), + fieldWithPath("_links").description("<> to other resources")))); } @Test @@ -355,25 +353,25 @@ public class ApiDocumentation { tag.put("name", "REST"); String tagLocation = this.mockMvc - .perform( - post("/tags").contentType(MediaTypes.HAL_JSON).content( - this.objectMapper.writeValueAsString(tag))) - .andExpect(status().isCreated()).andReturn().getResponse() - .getHeader("Location"); + .perform(post("/tags") + .contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(tag))) + .andExpect(status().isCreated()) + .andReturn().getResponse().getHeader("Location"); Map tagUpdate = new HashMap(); tagUpdate.put("name", "RESTful"); ConstrainedFields fields = new ConstrainedFields(TagPatchInput.class); - this.document.snippets( + this.mockMvc + .perform(patch(tagLocation) + .contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(tagUpdate))) + .andExpect(status().isNoContent()) + .andDo(this.documentationHandler.document( requestFields( - fields.withPath("name").description("The name of the tag"))); - - this.mockMvc.perform( - patch(tagLocation).contentType(MediaTypes.HAL_JSON).content( - this.objectMapper.writeValueAsString(tagUpdate))) - .andExpect(status().isNoContent()); + fields.withPath("name").description("The name of the tag")))); } private void createNote(String title, String body) {