From 50743f20c07ec78f69398c1c6d83497e0d38f0b9 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sun, 7 Jan 2018 17:05:18 +0200 Subject: [PATCH 1/4] update restdocs, move to spring-5 --- pom.xml | 1 - spring-5/pom.xml | 45 ++++ .../baeldung/restdocs}/CRUDController.java | 34 +-- .../java/com/baeldung/restdocs/CrudInput.java | 66 ++++++ .../baeldung/restdocs}/IndexController.java | 6 +- .../restdocs}/SpringRestDocsApplication.java | 2 +- spring-rest-docs/README.MD | 5 - spring-rest-docs/pom.xml | 112 ---------- .../src/docs/asciidocs/api-guide.adoc | 203 ------------------ .../src/main/java/com/example/CrudInput.java | 41 ---- .../src/main/resources/application.properties | 0 .../ApiDocumentationIntegrationTest.java | 181 ---------------- ...ngStartedDocumentationIntegrationTest.java | 147 ------------- 13 files changed, 134 insertions(+), 709 deletions(-) rename {spring-rest-docs/src/main/java/com/example => spring-5/src/main/java/com/baeldung/restdocs}/CRUDController.java (59%) create mode 100644 spring-5/src/main/java/com/baeldung/restdocs/CrudInput.java rename {spring-rest-docs/src/main/java/com/example => spring-5/src/main/java/com/baeldung/restdocs}/IndexController.java (79%) rename {spring-rest-docs/src/main/java/com/example => spring-5/src/main/java/com/baeldung/restdocs}/SpringRestDocsApplication.java (90%) delete mode 100644 spring-rest-docs/README.MD delete mode 100644 spring-rest-docs/pom.xml delete mode 100644 spring-rest-docs/src/docs/asciidocs/api-guide.adoc delete mode 100644 spring-rest-docs/src/main/java/com/example/CrudInput.java delete mode 100644 spring-rest-docs/src/main/resources/application.properties delete mode 100644 spring-rest-docs/src/test/java/com/example/ApiDocumentationIntegrationTest.java delete mode 100644 spring-rest-docs/src/test/java/com/example/GettingStartedDocumentationIntegrationTest.java diff --git a/pom.xml b/pom.xml index 68edf19cb2..863de4c20e 100644 --- a/pom.xml +++ b/pom.xml @@ -201,7 +201,6 @@ spring-protobuf spring-quartz spring-rest-angular - spring-rest-docs spring-rest-full spring-rest-query-language spring-rest diff --git a/spring-5/pom.xml b/spring-5/pom.xml index ac49e8d6f4..81e7ae3123 100644 --- a/spring-5/pom.xml +++ b/spring-5/pom.xml @@ -39,6 +39,10 @@ org.springframework.boot spring-boot-starter-webflux + + org.springframework.boot + spring-boot-starter-hateoas + org.projectreactor reactor-spring @@ -135,6 +139,22 @@ ${junit.platform.version} test + + org.springframework.restdocs + spring-restdocs-mockmvc + test + + + org.springframework.restdocs + spring-restdocs-webtestclient + test + + + org.springframework.restdocs + spring-restdocs-restassured + test + + @@ -163,6 +183,29 @@ + + org.asciidoctor + asciidoctor-maven-plugin + ${asciidoctor-plugin.version} + + + generate-docs + package + + process-asciidoc + + + html + book + + ${snippetsDirectory} + + src/docs/asciidocs + target/generated-docs + + + + @@ -199,6 +242,8 @@ 1.1.3 1.0 1.0 + 1.5.6 + ${project.build.directory}/generated-snippets diff --git a/spring-rest-docs/src/main/java/com/example/CRUDController.java b/spring-5/src/main/java/com/baeldung/restdocs/CRUDController.java similarity index 59% rename from spring-rest-docs/src/main/java/com/example/CRUDController.java rename to spring-5/src/main/java/com/baeldung/restdocs/CRUDController.java index ff8c91d6cd..9c8e436fa9 100644 --- a/spring-rest-docs/src/main/java/com/example/CRUDController.java +++ b/spring-5/src/main/java/com/baeldung/restdocs/CRUDController.java @@ -1,4 +1,4 @@ -package com.example; +package com.baeldung.restdocs; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; @@ -7,10 +7,14 @@ import java.util.List; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; @@ -18,8 +22,7 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("/crud") public class CRUDController { - @RequestMapping(method = RequestMethod.GET) - @ResponseStatus(HttpStatus.OK) + @GetMapping public List read(@RequestBody CrudInput crudInput) { List returnList = new ArrayList(); returnList.add(crudInput); @@ -27,29 +30,30 @@ public class CRUDController { } @ResponseStatus(HttpStatus.CREATED) - @RequestMapping(method = RequestMethod.POST) + @PostMapping public HttpHeaders save(@RequestBody CrudInput crudInput) { HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.setLocation(linkTo(CRUDController.class).slash(crudInput.getTitle()).toUri()); + httpHeaders.setLocation(linkTo(CRUDController.class).slash(crudInput.getId()).toUri()); return httpHeaders; } - @RequestMapping(value = "/{id}", method = RequestMethod.DELETE) + @DeleteMapping(value = "/{id}") @ResponseStatus(HttpStatus.OK) - HttpHeaders delete(@RequestBody CrudInput crudInput) { - HttpHeaders httpHeaders = new HttpHeaders(); - return httpHeaders; + HttpHeaders delete(@PathVariable("id") long id) { + return new HttpHeaders(); } - @RequestMapping(value = "/{id}", method = RequestMethod.PUT) + @PutMapping(value = "/{id}") @ResponseStatus(HttpStatus.ACCEPTED) void put(@PathVariable("id") long id, @RequestBody CrudInput crudInput) { } - @RequestMapping(value = "/{id}", method = RequestMethod.PATCH) - @ResponseStatus(HttpStatus.NO_CONTENT) - void patch(@PathVariable("id") long id, @RequestBody CrudInput crudInput) { - + @PatchMapping(value = "/{id}") + public List patch(@PathVariable("id") long id, @RequestBody CrudInput crudInput) { + List returnList = new ArrayList(); + crudInput.setId(id); + returnList.add(crudInput); + return returnList; } } diff --git a/spring-5/src/main/java/com/baeldung/restdocs/CrudInput.java b/spring-5/src/main/java/com/baeldung/restdocs/CrudInput.java new file mode 100644 index 0000000000..29046d7725 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/restdocs/CrudInput.java @@ -0,0 +1,66 @@ +package com.baeldung.restdocs; + +import java.net.URI; +import java.util.Collections; +import java.util.List; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class CrudInput { + + @NotNull + private long id; + + @NotBlank + private String title; + + private String body; + + private List tagUris; + + @JsonCreator + public CrudInput(@JsonProperty("id") long id, @JsonProperty("title") String title, @JsonProperty("body") String body, @JsonProperty("tags") List tagUris) { + this.id=id; + this.title = title; + this.body = body; + this.tagUris = tagUris == null ? Collections. emptyList() : tagUris; + } + + public String getTitle() { + return title; + } + + public String getBody() { + return body; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setBody(String body) { + this.body = body; + } + + public void setTagUris(List tagUris) { + this.tagUris = tagUris; + } + + @JsonProperty("tags") + public List getTagUris() { + return this.tagUris; + } + +} \ No newline at end of file diff --git a/spring-rest-docs/src/main/java/com/example/IndexController.java b/spring-5/src/main/java/com/baeldung/restdocs/IndexController.java similarity index 79% rename from spring-rest-docs/src/main/java/com/example/IndexController.java rename to spring-5/src/main/java/com/baeldung/restdocs/IndexController.java index 6b896da416..2c58d5fe6b 100644 --- a/spring-rest-docs/src/main/java/com/example/IndexController.java +++ b/spring-5/src/main/java/com/baeldung/restdocs/IndexController.java @@ -1,17 +1,17 @@ -package com.example; +package com.baeldung.restdocs; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import org.springframework.hateoas.ResourceSupport; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/") public class IndexController { - @RequestMapping(method = RequestMethod.GET) + @GetMapping public ResourceSupport index() { ResourceSupport index = new ResourceSupport(); index.add(linkTo(CRUDController.class).withRel("crud")); diff --git a/spring-rest-docs/src/main/java/com/example/SpringRestDocsApplication.java b/spring-5/src/main/java/com/baeldung/restdocs/SpringRestDocsApplication.java similarity index 90% rename from spring-rest-docs/src/main/java/com/example/SpringRestDocsApplication.java rename to spring-5/src/main/java/com/baeldung/restdocs/SpringRestDocsApplication.java index da09f9accc..02332ee7b6 100644 --- a/spring-rest-docs/src/main/java/com/example/SpringRestDocsApplication.java +++ b/spring-5/src/main/java/com/baeldung/restdocs/SpringRestDocsApplication.java @@ -1,4 +1,4 @@ -package com.example; +package com.baeldung.restdocs; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/spring-rest-docs/README.MD b/spring-rest-docs/README.MD deleted file mode 100644 index f5d001d126..0000000000 --- a/spring-rest-docs/README.MD +++ /dev/null @@ -1,5 +0,0 @@ -###The Course -The "REST With Spring" Classes: http://bit.ly/restwithspring - -###Relevant Articles: -- [Introduction to Spring REST Docs](http://www.baeldung.com/spring-rest-docs) diff --git a/spring-rest-docs/pom.xml b/spring-rest-docs/pom.xml deleted file mode 100644 index ffd3cb89b6..0000000000 --- a/spring-rest-docs/pom.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - 4.0.0 - - com.example - spring-rest-docs - 0.0.1-SNAPSHOT - jar - - spring-rest-docs - Demo project for Spring Boot - - - parent-boot-5 - com.baeldung - 0.0.1-SNAPSHOT - ../parent-boot-5 - - - - ${project.build.directory}/generated-snippets - 1.1.2.RELEASE - 2.2.0 - 1.5.3 - - - - - org.springframework.boot - spring-boot-starter-hateoas - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.restdocs - spring-restdocs-mockmvc - test - - - com.jayway.jsonpath - json-path - - - - - - - org.asciidoctor - asciidoctor-maven-plugin - ${asciidoctor-plugin.version} - - - generate-docs - package - - process-asciidoc - - - html - book - - ${snippetsDirectory} - - src/docs/asciidocs - target/generated-docs - - - - - - - - - - integration - - - - org.apache.maven.plugins - maven-surefire-plugin - - - integration-test - - test - - - - **/*LiveTest.java - - - **/*IntegrationTest.java - - - - - - - json - - - - - - - - - diff --git a/spring-rest-docs/src/docs/asciidocs/api-guide.adoc b/spring-rest-docs/src/docs/asciidocs/api-guide.adoc deleted file mode 100644 index 9fbe74c072..0000000000 --- a/spring-rest-docs/src/docs/asciidocs/api-guide.adoc +++ /dev/null @@ -1,203 +0,0 @@ -= RESTful Notes API Guide -Baeldung; -:doctype: book -:icons: font -:source-highlighter: highlightjs -:toc: left -:toclevels: 4 -:sectlinks: - -[[overview]] -= Overview - -[[overview-http-verbs]] -== HTTP verbs - -RESTful notes tries to adhere as closely as possible to standard HTTP and REST conventions in its -use of HTTP verbs. - -|=== -| Verb | Usage - -| `GET` -| Used to retrieve a resource - -| `POST` -| Used to create a new resource - -| `PATCH` -| Used to update an existing resource, including partial updates - -| `DELETE` -| Used to delete an existing resource -|=== - -RESTful notes tries to adhere as closely as possible to standard HTTP and REST conventions in its -use of HTTP status codes. - -|=== -| Status code | Usage - -| `200 OK` -| The request completed successfully - -| `201 Created` -| A new resource has been created successfully. The resource's URI is available from the response's -`Location` header - -| `204 No Content` -| An update to an existing resource has been applied successfully - -| `400 Bad Request` -| The request was malformed. The response body will include an error providing further information - -| `404 Not Found` -| The requested resource did not exist -|=== - -[[overview-headers]] -== Headers - -Every response has the following header(s): - -include::{snippets}/headers-example/response-headers.adoc[] - -[[overview-hypermedia]] -== Hypermedia - -RESTful Notes uses hypermedia and resources include links to other resources in their -responses. Responses are in http://stateless.co/hal_specification.html[Hypertext Application -from resource to resource. -Language (HAL)] format. Links can be found beneath the `_links` key. Users of the API should -not create URIs themselves, instead they should use the above-described links to navigate - -[[resources]] -= Resources - - - -[[resources-index]] -== Index - -The index provides the entry point into the service. - -[[resources-index-access]] -=== Accessing the index - -A `GET` request is used to access the index - -==== Response structure - -include::{snippets}/index-example/http-response.adoc[] - -==== Example response - -include::{snippets}/index-example/http-response.adoc[] - -==== Example request - -include::{snippets}/index-example/http-request.adoc[] - -==== CURL request - -include::{snippets}/index-example/curl-request.adoc[] - -[[resources-index-links]] -==== Links - -include::{snippets}/index-example/links.adoc[] - - -[[resources-CRUD]] -== CRUD REST Service - -The CRUD provides the entry point into the service. - -[[resources-crud-access]] -=== Accessing the crud GET - -A `GET` request is used to access the CRUD read - -==== Response structure - -include::{snippets}/crud-get-example/http-request.adoc[] - -==== Example response - -include::{snippets}/crud-get-example/http-response.adoc[] - -==== CURL request - -include::{snippets}/crud-get-example/curl-request.adoc[] - -[[resources-crud-access]] -=== Accessing the crud POST - -A `POST` request is used to access the CRUD create - -==== Response structure - -include::{snippets}/crud-create-example/http-request.adoc[] - -==== Example response - -include::{snippets}/crud-create-example/http-response.adoc[] - -==== CURL request - -include::{snippets}/crud-create-example/curl-request.adoc[] - -[[resources-crud-access]] -=== Accessing the crud DELETE - -A `DELETE` request is used to access the CRUD create - -==== Response structure - -include::{snippets}/crud-delete-example/http-request.adoc[] - -==== Example response - -include::{snippets}/crud-delete-example/http-response.adoc[] - -==== CURL request - -include::{snippets}/crud-delete-example/curl-request.adoc[] - -[[resources-crud-access]] -=== Accessing the crud PATCH - -A `PATCH` request is used to access the CRUD create - -==== Response structure - -include::{snippets}/crud-patch-example/http-request.adoc[] - -==== Example response - -include::{snippets}/crud-patch-example/http-response.adoc[] - -==== CURL request - -include::{snippets}/crud-patch-example/curl-request.adoc[] - -[[resources-crud-access]] -=== Accessing the crud PUT - -A `PUT` request is used to access the CRUD create - -==== Response structure - -include::{snippets}/crud-put-example/http-request.adoc[] - -==== Example response - -include::{snippets}/crud-put-example/http-response.adoc[] - -==== CURL request - -include::{snippets}/crud-put-example/curl-request.adoc[] - - - - diff --git a/spring-rest-docs/src/main/java/com/example/CrudInput.java b/spring-rest-docs/src/main/java/com/example/CrudInput.java deleted file mode 100644 index 36ad67eb21..0000000000 --- a/spring-rest-docs/src/main/java/com/example/CrudInput.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.example; - -import java.net.URI; -import java.util.Collections; -import java.util.List; - -import org.hibernate.validator.constraints.NotBlank; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -public class CrudInput { - - // @NotBlank - private final String title; - - private final String body; - - private final List tagUris; - - @JsonCreator - public CrudInput(@JsonProperty("title") String title, @JsonProperty("body") String body, @JsonProperty("tags") List tagUris) { - this.title = title; - this.body = body; - this.tagUris = tagUris == null ? Collections. emptyList() : tagUris; - } - - public String getTitle() { - return title; - } - - public String getBody() { - return body; - } - - @JsonProperty("tags") - public List getTagUris() { - return this.tagUris; - } - -} \ No newline at end of file diff --git a/spring-rest-docs/src/main/resources/application.properties b/spring-rest-docs/src/main/resources/application.properties deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/spring-rest-docs/src/test/java/com/example/ApiDocumentationIntegrationTest.java b/spring-rest-docs/src/test/java/com/example/ApiDocumentationIntegrationTest.java deleted file mode 100644 index 1c3aef4845..0000000000 --- a/spring-rest-docs/src/test/java/com/example/ApiDocumentationIntegrationTest.java +++ /dev/null @@ -1,181 +0,0 @@ -package com.example; - -import static java.util.Collections.singletonList; -import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; -import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders; -import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel; -import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; -import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -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.MockMvcResultMatchers.status; -import static org.springframework.util.StringUtils.collectionToDelimitedString; - -import java.util.HashMap; -import java.util.Map; - -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.test.context.SpringBootTest; -import org.springframework.hateoas.MediaTypes; -import org.springframework.restdocs.RestDocumentation; -import org.springframework.restdocs.constraints.ConstraintDescriptions; -import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; -import org.springframework.restdocs.payload.FieldDescriptor; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -import com.fasterxml.jackson.databind.ObjectMapper; - -@RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest(classes = SpringRestDocsApplication.class) -@WebAppConfiguration -public class ApiDocumentationIntegrationTest { - - @Rule - public final RestDocumentation restDocumentation = new RestDocumentation("target/generated-snippets"); - - @Autowired - private WebApplicationContext context; - - @Autowired - private ObjectMapper objectMapper; - - private RestDocumentationResultHandler document; - - private MockMvc mockMvc; - - @Before - public void setUp() { - this.document = document("{method-name}", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).apply(documentationConfiguration(this.restDocumentation)).alwaysDo(this.document).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()); - } - - @Test - public void indexExample() throws Exception { - this.document.snippets(links(linkWithRel("crud").description("The <>")), responseFields(fieldWithPath("_links").description("<> to other resources"))); - this.mockMvc.perform(get("/")).andExpect(status().isOk()); - } - - @Test - public void crudGetExample() throws Exception { - - Map tag = new HashMap<>(); - tag.put("name", "GET"); - - String tagLocation = this.mockMvc.perform(get("/crud").contentType(MediaTypes.HAL_JSON).content(this.objectMapper.writeValueAsString(tag))).andExpect(status().isOk()).andReturn().getResponse().getHeader("Location"); - - Map crud = new HashMap<>(); - crud.put("title", "Sample Model"); - crud.put("body", "http://www.baeldung.com/"); - crud.put("tags", singletonList(tagLocation)); - - this.mockMvc.perform(get("/crud").contentType(MediaTypes.HAL_JSON).content(this.objectMapper.writeValueAsString(crud))).andExpect(status().isOk()); - } - - @Test - public void crudCreateExample() throws Exception { - Map tag = new HashMap<>(); - tag.put("name", "CREATE"); - - String tagLocation = this.mockMvc.perform(post("/crud").contentType(MediaTypes.HAL_JSON).content(this.objectMapper.writeValueAsString(tag))).andExpect(status().isCreated()).andReturn().getResponse().getHeader("Location"); - - Map crud = new HashMap<>(); - crud.put("title", "Sample Model"); - crud.put("body", "http://www.baeldung.com/"); - crud.put("tags", singletonList(tagLocation)); - - ConstrainedFields fields = new ConstrainedFields(CrudInput.class); - this.document.snippets(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("/crud").contentType(MediaTypes.HAL_JSON).content(this.objectMapper.writeValueAsString(crud))).andExpect(status().isCreated()); - - } - - @Test - public void crudDeleteExample() throws Exception { - - Map tag = new HashMap<>(); - tag.put("name", "DELETE"); - - String tagLocation = this.mockMvc.perform(delete("/crud/10").contentType(MediaTypes.HAL_JSON).content(this.objectMapper.writeValueAsString(tag))).andExpect(status().isOk()).andReturn().getResponse().getHeader("Location"); - - Map crud = new HashMap<>(); - crud.put("title", "Sample Model"); - crud.put("body", "http://www.baeldung.com/"); - crud.put("tags", singletonList(tagLocation)); - - this.mockMvc.perform(delete("/crud/10").contentType(MediaTypes.HAL_JSON).content(this.objectMapper.writeValueAsString(crud))).andExpect(status().isOk()); - } - - @Test - public void crudPatchExample() throws Exception { - - Map tag = new HashMap<>(); - tag.put("name", "PATCH"); - - String tagLocation = this.mockMvc.perform(patch("/crud/10").contentType(MediaTypes.HAL_JSON).content(this.objectMapper.writeValueAsString(tag))).andExpect(status().isNoContent()).andReturn().getResponse().getHeader("Location"); - - Map crud = new HashMap<>(); - crud.put("title", "Sample Model"); - crud.put("body", "http://www.baeldung.com/"); - crud.put("tags", singletonList(tagLocation)); - - this.mockMvc.perform(patch("/crud/10").contentType(MediaTypes.HAL_JSON).content(this.objectMapper.writeValueAsString(crud))).andExpect(status().isNoContent()); - } - - @Test - public void crudPutExample() throws Exception { - Map tag = new HashMap<>(); - tag.put("name", "PUT"); - - String tagLocation = this.mockMvc.perform(put("/crud/10").contentType(MediaTypes.HAL_JSON).content(this.objectMapper.writeValueAsString(tag))).andExpect(status().isAccepted()).andReturn().getResponse().getHeader("Location"); - - Map crud = new HashMap<>(); - crud.put("title", "Sample Model"); - crud.put("body", "http://www.baeldung.com/"); - crud.put("tags", singletonList(tagLocation)); - - this.mockMvc.perform(put("/crud/10").contentType(MediaTypes.HAL_JSON).content(this.objectMapper.writeValueAsString(crud))).andExpect(status().isAccepted()); - } - - @Test - public void contextLoads() { - } - - private static class ConstrainedFields { - - private final ConstraintDescriptions constraintDescriptions; - - ConstrainedFields(Class input) { - this.constraintDescriptions = new ConstraintDescriptions(input); - } - - private FieldDescriptor withPath(String path) { - return fieldWithPath(path).attributes(key("constraints").value(collectionToDelimitedString(this.constraintDescriptions.descriptionsForProperty(path), ". "))); - } - } - -} diff --git a/spring-rest-docs/src/test/java/com/example/GettingStartedDocumentationIntegrationTest.java b/spring-rest-docs/src/test/java/com/example/GettingStartedDocumentationIntegrationTest.java deleted file mode 100644 index 3300fc519c..0000000000 --- a/spring-rest-docs/src/test/java/com/example/GettingStartedDocumentationIntegrationTest.java +++ /dev/null @@ -1,147 +0,0 @@ -package com.example; - -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; -import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; -import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -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.test.context.SpringBootTest; -import org.springframework.hateoas.MediaTypes; -import org.springframework.restdocs.RestDocumentation; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -import com.fasterxml.jackson.databind.ObjectMapper; - -@RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest(classes = SpringRestDocsApplication.class) -@WebAppConfiguration -public class GettingStartedDocumentationIntegrationTest { - - @Rule - public final RestDocumentation restDocumentation = new RestDocumentation("target/generated-snippets"); - - @Autowired - private ObjectMapper objectMapper; - - @Autowired - private WebApplicationContext context; - - private MockMvc mockMvc; - - @Before - public void setUp() { - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).apply(documentationConfiguration(this.restDocumentation)).alwaysDo(document("{method-name}/{step}/", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()))).build(); - } - - @Test - public void index() throws Exception { - this.mockMvc.perform(get("/").accept(MediaTypes.HAL_JSON)).andExpect(status().isOk()).andExpect(jsonPath("_links.crud", is(notNullValue()))).andExpect(jsonPath("_links.crud", is(notNullValue()))); - } - - // String createNote() throws Exception { - // Map note = new HashMap(); - // note.put("title", "Note creation with cURL"); - // note.put("body", "An example of how to create a note using curl"); - // String noteLocation = this.mockMvc.perform(post("/crud") - // .contentType(MediaTypes.HAL_JSON) - // .content(objectMapper.writeValueAsString(note))) - // .andExpect(status().isCreated()) - // .andExpect(header().string("Location", notNullValue())) - // .andReturn() - // .getResponse() - // .getHeader("Location"); - // return noteLocation; - // } - // - // MvcResult getNote(String noteLocation) throws Exception { - // return this.mockMvc.perform(get(noteLocation)) - // .andExpect(status().isOk()) - // .andExpect(jsonPath("title", is(notNullValue()))) - // .andExpect(jsonPath("body", is(notNullValue()))) - // .andExpect(jsonPath("_links.crud", is(notNullValue()))) - // .andReturn(); - // } - // - // - // String createTag() throws Exception, JsonProcessingException { - // Map tag = new HashMap(); - // tag.put("name", "getting-started"); - // String tagLocation = this.mockMvc.perform(post("/crud") - // .contentType(MediaTypes.HAL_JSON) - // .content(objectMapper.writeValueAsString(tag))) - // .andExpect(status().isCreated()) - // .andExpect(header().string("Location", notNullValue())) - // .andReturn() - // .getResponse() - // .getHeader("Location"); - // return tagLocation; - // } - // - // void getTag(String tagLocation) throws Exception { - // this.mockMvc.perform(get(tagLocation)).andExpect(status().isOk()) - // .andExpect(jsonPath("name", is(notNullValue()))) - // .andExpect(jsonPath("_links.tagged-notes", is(notNullValue()))); - // } - // - // String createTaggedNote(String tag) throws Exception { - // Map note = new HashMap(); - // note.put("title", "Tagged note creation with cURL"); - // note.put("body", "An example of how to create a tagged note using cURL"); - // note.put("tags", Arrays.asList(tag)); - // - // String noteLocation = this.mockMvc.perform(post("/notes") - // .contentType(MediaTypes.HAL_JSON) - // .content(objectMapper.writeValueAsString(note))) - // .andExpect(status().isCreated()) - // .andExpect(header().string("Location", notNullValue())) - // .andReturn() - // .getResponse() - // .getHeader("Location"); - // return noteLocation; - // } - // - // void getTags(String noteTagsLocation) throws Exception { - // this.mockMvc.perform(get(noteTagsLocation)) - // .andExpect(status().isOk()) - // .andExpect(jsonPath("_embedded.tags", hasSize(1))); - // } - // - // void tagExistingNote(String noteLocation, String tagLocation) throws Exception { - // Map update = new HashMap(); - // update.put("tags", Arrays.asList(tagLocation)); - // this.mockMvc.perform(patch(noteLocation) - // .contentType(MediaTypes.HAL_JSON) - // .content(objectMapper.writeValueAsString(update))) - // .andExpect(status().isNoContent()); - // } - // - // MvcResult getTaggedExistingNote(String noteLocation) throws Exception { - // return this.mockMvc.perform(get(noteLocation)).andExpect(status().isOk()).andReturn(); - // } - // - // void getTagsForExistingNote(String noteTagsLocation) throws Exception { - // this.mockMvc.perform(get(noteTagsLocation)) - // .andExpect(status().isOk()).andExpect(jsonPath("_embedded.tags", hasSize(1))); - // } - // - // private String getLink(MvcResult result, String rel) - // throws UnsupportedEncodingException { - // return JsonPath.parse(result.getResponse().getContentAsString()).read("_links." + rel + ".href"); - // } - -} From 630acd7959ff8e3d94b64e7518bd39d7a4894992 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sun, 7 Jan 2018 17:09:37 +0200 Subject: [PATCH 2/4] formatting, add tests --- spring-5/pom.xml | 5 +- ...ApiDocumentationJUnit4IntegrationTest.java | 184 ++++++++++++++++++ ...ApiDocumentationJUnit5IntegrationTest.java | 181 +++++++++++++++++ 3 files changed, 368 insertions(+), 2 deletions(-) create mode 100644 spring-5/src/test/java/com/baeldung/restdocs/ApiDocumentationJUnit4IntegrationTest.java create mode 100644 spring-5/src/test/java/com/baeldung/restdocs/ApiDocumentationJUnit5IntegrationTest.java diff --git a/spring-5/pom.xml b/spring-5/pom.xml index 81e7ae3123..a76730f628 100644 --- a/spring-5/pom.xml +++ b/spring-5/pom.xml @@ -139,7 +139,8 @@ ${junit.platform.version} test - + + org.springframework.restdocs spring-restdocs-mockmvc test @@ -183,7 +184,7 @@ - + org.asciidoctor asciidoctor-maven-plugin ${asciidoctor-plugin.version} diff --git a/spring-5/src/test/java/com/baeldung/restdocs/ApiDocumentationJUnit4IntegrationTest.java b/spring-5/src/test/java/com/baeldung/restdocs/ApiDocumentationJUnit4IntegrationTest.java new file mode 100644 index 0000000000..de1d3f8b6a --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/restdocs/ApiDocumentationJUnit4IntegrationTest.java @@ -0,0 +1,184 @@ +package com.baeldung.restdocs; + +import com.baeldung.restdocs.CrudInput; +import com.baeldung.restdocs.SpringRestDocsApplication; +import com.fasterxml.jackson.databind.ObjectMapper; +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.test.context.SpringBootTest; +import org.springframework.hateoas.MediaTypes; +import org.springframework.restdocs.JUnitRestDocumentation; +import org.springframework.restdocs.constraints.ConstraintDescriptions; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import java.util.HashMap; +import java.util.Map; + +import static java.util.Collections.singletonList; +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders; +import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel; +import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.util.StringUtils.collectionToDelimitedString; +import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SpringRestDocsApplication.class) +public class ApiDocumentationJUnit4IntegrationTest { + + @Rule + public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("target/generated-snippets"); + + @Autowired + private WebApplicationContext context; + + @Autowired + private ObjectMapper objectMapper; + + private MockMvc mockMvc; + + @Before + public void setUp() { + + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) + .apply(documentationConfiguration(this.restDocumentation)) + .alwaysDo(document("{method-name}", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()))) + .build(); + } + + @Test + public void indexExample() throws Exception { + this.mockMvc.perform(get("/")) + .andExpect(status().isOk()) + .andDo(document("index-example", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), links(linkWithRel("crud").description("The CRUD resource")), responseFields(subsectionWithPath("_links").description("Links to other resources")), + responseHeaders(headerWithName("Content-Type").description("The Content-Type of the payload, e.g. `application/hal+json`")))); + } + + @Test + public void crudGetExample() throws Exception { + + Map tag = new HashMap<>(); + tag.put("name", "GET"); + + String tagLocation = this.mockMvc.perform(get("/crud").contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(tag))) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getHeader("Location"); + + Map crud = new HashMap<>(); + crud.put("id", 1L); + crud.put("title", "Sample Model"); + crud.put("body", "http://www.baeldung.com/"); + crud.put("tags", singletonList(tagLocation)); + + ConstraintDescriptions desc = new ConstraintDescriptions(CrudInput.class); + + this.mockMvc.perform(get("/crud").contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(crud))) + .andExpect(status().isOk()) + .andDo(document("crud-get-example", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestFields(fieldWithPath("id").description("The id of the input" + collectionToDelimitedString(desc.descriptionsForProperty("id"), ". ")), + fieldWithPath("title").description("The title of the input"), fieldWithPath("body").description("The body of the input"), fieldWithPath("tags").description("An array of tag resource URIs")))); + } + + @Test + public void crudCreateExample() throws Exception { + Map tag = new HashMap<>(); + tag.put("name", "CREATE"); + + String tagLocation = this.mockMvc.perform(post("/crud").contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(tag))) + .andExpect(status().isCreated()) + .andReturn() + .getResponse() + .getHeader("Location"); + + Map crud = new HashMap<>(); + crud.put("id", 2L); + crud.put("title", "Sample Model"); + crud.put("body", "http://www.baeldung.com/"); + crud.put("tags", singletonList(tagLocation)); + + this.mockMvc.perform(post("/crud").contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(crud))) + .andExpect(status().isCreated()) + .andDo(document("crud-create-example", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestFields(fieldWithPath("id").description("The id of the input"), fieldWithPath("title").description("The title of the input"), + fieldWithPath("body").description("The body of the input"), fieldWithPath("tags").description("An array of tag resource URIs")))); + } + + @Test + public void crudDeleteExample() throws Exception { + this.mockMvc.perform(delete("/crud/{id}", 10)) + .andExpect(status().isOk()) + .andDo(document("crud-delete-example", pathParameters(parameterWithName("id").description("The id of the input to delete")))); + } + + @Test + public void crudPatchExample() throws Exception { + + Map tag = new HashMap<>(); + tag.put("name", "PATCH"); + + String tagLocation = this.mockMvc.perform(patch("/crud/{id}", 10).contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(tag))) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getHeader("Location"); + + Map crud = new HashMap<>(); + crud.put("title", "Sample Model Patch"); + crud.put("body", "http://www.baeldung.com/"); + crud.put("tags", singletonList(tagLocation)); + + this.mockMvc.perform(patch("/crud/{id}", 10).contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(crud))) + .andExpect(status().isOk()); + } + + @Test + public void crudPutExample() throws Exception { + Map tag = new HashMap<>(); + tag.put("name", "PUT"); + + String tagLocation = this.mockMvc.perform(put("/crud/{id}", 10).contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(tag))) + .andExpect(status().isAccepted()) + .andReturn() + .getResponse() + .getHeader("Location"); + + Map crud = new HashMap<>(); + crud.put("title", "Sample Model"); + crud.put("body", "http://www.baeldung.com/"); + crud.put("tags", singletonList(tagLocation)); + + this.mockMvc.perform(put("/crud/{id}", 10).contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(crud))) + .andExpect(status().isAccepted()); + } + + @Test + public void contextLoads() { + } + +} diff --git a/spring-5/src/test/java/com/baeldung/restdocs/ApiDocumentationJUnit5IntegrationTest.java b/spring-5/src/test/java/com/baeldung/restdocs/ApiDocumentationJUnit5IntegrationTest.java new file mode 100644 index 0000000000..d915a4fdde --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/restdocs/ApiDocumentationJUnit5IntegrationTest.java @@ -0,0 +1,181 @@ +package com.baeldung.restdocs; + +import static java.util.Collections.singletonList; +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders; +import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel; +import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.util.StringUtils.collectionToDelimitedString; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.hateoas.MediaTypes; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.restdocs.constraints.ConstraintDescriptions; +import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import com.baeldung.restdocs.CrudInput; +import com.baeldung.restdocs.SpringRestDocsApplication; +import com.fasterxml.jackson.databind.ObjectMapper; + +@ExtendWith({ RestDocumentationExtension.class, SpringExtension.class }) +@SpringBootTest(classes = SpringRestDocsApplication.class) +public class ApiDocumentationJUnit5IntegrationTest { + + @Autowired + private ObjectMapper objectMapper; + + private MockMvc mockMvc; + + @BeforeEach + public void setUp(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) { + this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) + .apply(documentationConfiguration(restDocumentation)) + .alwaysDo(document("{method-name}", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()))) + .build(); + } + + @Test + public void indexExample() throws Exception { + this.mockMvc.perform(get("/")) + .andExpect(status().isOk()) + .andDo(document("index-example", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), links(linkWithRel("crud").description("The CRUD resource")), responseFields(subsectionWithPath("_links").description("Links to other resources")), + responseHeaders(headerWithName("Content-Type").description("The Content-Type of the payload, e.g. `application/hal+json`")))); + } + + @Test + public void crudGetExample() throws Exception { + + Map tag = new HashMap<>(); + tag.put("name", "GET"); + + String tagLocation = this.mockMvc.perform(get("/crud").contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(tag))) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getHeader("Location"); + + Map crud = new HashMap<>(); + crud.put("id", 1L); + crud.put("title", "Sample Model"); + crud.put("body", "http://www.baeldung.com/"); + crud.put("tags", singletonList(tagLocation)); + + ConstraintDescriptions desc = new ConstraintDescriptions(CrudInput.class); + + this.mockMvc.perform(get("/crud").contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(crud))) + .andExpect(status().isOk()) + .andDo(document("crud-get-example", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestFields(fieldWithPath("id").description("The id of the input" + collectionToDelimitedString(desc.descriptionsForProperty("id"), ". ")), + fieldWithPath("title").description("The title of the input"), fieldWithPath("body").description("The body of the input"), fieldWithPath("tags").description("An array of tag resource URIs")))); + } + + @Test + public void crudCreateExample() throws Exception { + Map tag = new HashMap<>(); + tag.put("name", "CREATE"); + + String tagLocation = this.mockMvc.perform(post("/crud").contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(tag))) + .andExpect(status().isCreated()) + .andReturn() + .getResponse() + .getHeader("Location"); + + Map crud = new HashMap<>(); + crud.put("id", 2L); + crud.put("title", "Sample Model"); + crud.put("body", "http://www.baeldung.com/"); + crud.put("tags", singletonList(tagLocation)); + + this.mockMvc.perform(post("/crud").contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(crud))) + .andExpect(status().isCreated()) + .andDo(document("crud-create-example", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestFields(fieldWithPath("id").description("The id of the input"), fieldWithPath("title").description("The title of the input"), + fieldWithPath("body").description("The body of the input"), fieldWithPath("tags").description("An array of tag resource URIs")))); + } + + @Test + public void crudDeleteExample() throws Exception { + this.mockMvc.perform(delete("/crud/{id}", 10)) + .andExpect(status().isOk()) + .andDo(document("crud-delete-example", pathParameters(parameterWithName("id").description("The id of the input to delete")))); + } + + @Test + public void crudPatchExample() throws Exception { + + Map tag = new HashMap<>(); + tag.put("name", "PATCH"); + + String tagLocation = this.mockMvc.perform(patch("/crud/{id}", 10).contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(tag))) + .andExpect(status().isOk()) + .andReturn() + .getResponse() + .getHeader("Location"); + + Map crud = new HashMap<>(); + crud.put("title", "Sample Model Patch"); + crud.put("body", "http://www.baeldung.com/"); + crud.put("tags", singletonList(tagLocation)); + + this.mockMvc.perform(patch("/crud/{id}", 10).contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(crud))) + .andExpect(status().isOk()); + } + + @Test + public void crudPutExample() throws Exception { + Map tag = new HashMap<>(); + tag.put("name", "PUT"); + + String tagLocation = this.mockMvc.perform(put("/crud/{id}", 10).contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(tag))) + .andExpect(status().isAccepted()) + .andReturn() + .getResponse() + .getHeader("Location"); + + Map crud = new HashMap<>(); + crud.put("title", "Sample Model"); + crud.put("body", "http://www.baeldung.com/"); + crud.put("tags", singletonList(tagLocation)); + + this.mockMvc.perform(put("/crud/{id}", 10).contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(crud))) + .andExpect(status().isAccepted()); + } + + @Test + public void contextLoads() { + } + +} From 3d233f5ede85e00163dbfa6ff1dd7e7d5009d101 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Sun, 7 Jan 2018 17:12:07 +0200 Subject: [PATCH 3/4] add api guide --- spring-5/src/docs/asciidocs/api-guide.adoc | 195 +++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 spring-5/src/docs/asciidocs/api-guide.adoc diff --git a/spring-5/src/docs/asciidocs/api-guide.adoc b/spring-5/src/docs/asciidocs/api-guide.adoc new file mode 100644 index 0000000000..6eadfb5efd --- /dev/null +++ b/spring-5/src/docs/asciidocs/api-guide.adoc @@ -0,0 +1,195 @@ += RESTful Notes API Guide +Baeldung; +:doctype: book +:icons: font +:source-highlighter: highlightjs +:toc: left +:toclevels: 4 +:sectlinks: + +[[overview]] += Overview + +[[overview-http-verbs]] +== HTTP verbs + +RESTful notes tries to adhere as closely as possible to standard HTTP and REST conventions in its +use of HTTP verbs. + +|=== +| Verb | Usage + +| `GET` +| Used to retrieve a resource + +| `POST` +| Used to create a new resource + +| `PATCH` +| Used to update an existing resource, including partial updates + +| `DELETE` +| Used to delete an existing resource +|=== + +RESTful notes tries to adhere as closely as possible to standard HTTP and REST conventions in its +use of HTTP status codes. + +|=== +| Status code | Usage + +| `200 OK` +| The request completed successfully + +| `201 Created` +| A new resource has been created successfully. The resource's URI is available from the response's +`Location` header + +| `204 No Content` +| An update to an existing resource has been applied successfully + +| `400 Bad Request` +| The request was malformed. The response body will include an error providing further information + +| `404 Not Found` +| The requested resource did not exist +|=== + +[[overview-hypermedia]] +== Hypermedia + +RESTful Notes uses hypermedia and resources include links to other resources in their +responses. Responses are in http://stateless.co/hal_specification.html[Hypertext Application +from resource to resource. +Language (HAL)] format. Links can be found beneath the `_links` key. Users of the API should +not create URIs themselves, instead they should use the above-described links to navigate + +[[resources]] += Resources + + + +[[resources-index]] +== Index + +The index provides the entry point into the service. + +[[resources-index-access]] +=== Accessing the index + +A `GET` request is used to access the index + +==== Request structure + +include::{snippets}/index-example/http-request.adoc[] + +==== Example response + +include::{snippets}/index-example/http-response.adoc[] + +==== CURL request + +include::{snippets}/index-example/curl-request.adoc[] + +[[resources-index-links]] +==== Links + +include::{snippets}/index-example/links.adoc[] + + +[[resources-CRUD]] +== CRUD REST Service + +The CRUD provides the entry point into the service. + +[[resources-crud-get]] +=== Accessing the crud GET + +A `GET` request is used to access the CRUD read. + +==== Request structure + +include::{snippets}/crud-get-example/http-request.adoc[] + +==== Example response + +include::{snippets}/crud-get-example/http-response.adoc[] + +==== CURL request + +include::{snippets}/crud-get-example/curl-request.adoc[] + +[[resources-crud-post]] +=== Accessing the crud POST + +A `POST` request is used to access the CRUD create. + +==== Request structure + +include::{snippets}/crud-create-example/http-request.adoc[] + +==== Example response + +include::{snippets}/crud-create-example/http-response.adoc[] + +==== CURL request + +include::{snippets}/crud-create-example/curl-request.adoc[] + +[[resources-crud-delete]] +=== Accessing the crud DELETE + +A `DELETE` request is used to access the CRUD delete. + +==== Request structure + +include::{snippets}/crud-delete-example/http-request.adoc[] + +==== Path Parameters +include::{snippets}/crud-delete-example/path-parameters.adoc[] + +==== Example response + +include::{snippets}/crud-delete-example/http-response.adoc[] + +==== CURL request + +include::{snippets}/crud-delete-example/curl-request.adoc[] + +[[resources-crud-patch]] +=== Accessing the crud PATCH + +A `PATCH` request is used to access the CRUD update. + +==== Request structure + +include::{snippets}/crud-patch-example/http-request.adoc[] + +==== Example response + +include::{snippets}/crud-patch-example/http-response.adoc[] + +==== CURL request + +include::{snippets}/crud-patch-example/curl-request.adoc[] + +[[resources-crud-put]] +=== Accessing the crud PUT + +A `PUT` request is used to access the CRUD update. + +==== Request structure + +include::{snippets}/crud-put-example/http-request.adoc[] + +==== Example response + +include::{snippets}/crud-put-example/http-response.adoc[] + +==== CURL request + +include::{snippets}/crud-put-example/curl-request.adoc[] + + + + From fa2e225d6306ab78d00b45be666f208374991476 Mon Sep 17 00:00:00 2001 From: Loredana Crusoveanu Date: Mon, 8 Jan 2018 21:13:31 +0200 Subject: [PATCH 4/4] add requested changes --- .../com/baeldung/restdocs/CRUDController.java | 15 ++++++---- ...ApiDocumentationJUnit4IntegrationTest.java | 24 +++++++-------- ...ApiDocumentationJUnit5IntegrationTest.java | 30 +++++++------------ 3 files changed, 30 insertions(+), 39 deletions(-) diff --git a/spring-5/src/main/java/com/baeldung/restdocs/CRUDController.java b/spring-5/src/main/java/com/baeldung/restdocs/CRUDController.java index 9c8e436fa9..f6183bc79e 100644 --- a/spring-5/src/main/java/com/baeldung/restdocs/CRUDController.java +++ b/spring-5/src/main/java/com/baeldung/restdocs/CRUDController.java @@ -5,8 +5,11 @@ import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import java.util.ArrayList; import java.util.List; +import javax.validation.Valid; + import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; @@ -23,33 +26,33 @@ import org.springframework.web.bind.annotation.RestController; public class CRUDController { @GetMapping - public List read(@RequestBody CrudInput crudInput) { - List returnList = new ArrayList(); + public List read(@RequestBody @Valid CrudInput crudInput) { + List returnList = new ArrayList<>(); returnList.add(crudInput); return returnList; } @ResponseStatus(HttpStatus.CREATED) @PostMapping - public HttpHeaders save(@RequestBody CrudInput crudInput) { + public HttpHeaders save(@RequestBody @Valid CrudInput crudInput) { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setLocation(linkTo(CRUDController.class).slash(crudInput.getId()).toUri()); return httpHeaders; } - @DeleteMapping(value = "/{id}") + @DeleteMapping("/{id}") @ResponseStatus(HttpStatus.OK) HttpHeaders delete(@PathVariable("id") long id) { return new HttpHeaders(); } - @PutMapping(value = "/{id}") + @PutMapping("/{id}") @ResponseStatus(HttpStatus.ACCEPTED) void put(@PathVariable("id") long id, @RequestBody CrudInput crudInput) { } - @PatchMapping(value = "/{id}") + @PatchMapping("/{id}") public List patch(@PathVariable("id") long id, @RequestBody CrudInput crudInput) { List returnList = new ArrayList(); crudInput.setId(id); diff --git a/spring-5/src/test/java/com/baeldung/restdocs/ApiDocumentationJUnit4IntegrationTest.java b/spring-5/src/test/java/com/baeldung/restdocs/ApiDocumentationJUnit4IntegrationTest.java index de1d3f8b6a..20f0a47d83 100644 --- a/spring-5/src/test/java/com/baeldung/restdocs/ApiDocumentationJUnit4IntegrationTest.java +++ b/spring-5/src/test/java/com/baeldung/restdocs/ApiDocumentationJUnit4IntegrationTest.java @@ -75,20 +75,18 @@ public class ApiDocumentationJUnit4IntegrationTest { @Test public void crudGetExample() throws Exception { - Map tag = new HashMap<>(); - tag.put("name", "GET"); + Map crud = new HashMap<>(); + crud.put("id", 1L); + crud.put("title", "Sample Model"); + crud.put("body", "http://www.baeldung.com/"); String tagLocation = this.mockMvc.perform(get("/crud").contentType(MediaTypes.HAL_JSON) - .content(this.objectMapper.writeValueAsString(tag))) + .content(this.objectMapper.writeValueAsString(crud))) .andExpect(status().isOk()) .andReturn() .getResponse() .getHeader("Location"); - Map crud = new HashMap<>(); - crud.put("id", 1L); - crud.put("title", "Sample Model"); - crud.put("body", "http://www.baeldung.com/"); crud.put("tags", singletonList(tagLocation)); ConstraintDescriptions desc = new ConstraintDescriptions(CrudInput.class); @@ -102,20 +100,18 @@ public class ApiDocumentationJUnit4IntegrationTest { @Test public void crudCreateExample() throws Exception { - Map tag = new HashMap<>(); - tag.put("name", "CREATE"); + Map crud = new HashMap<>(); + crud.put("id", 2L); + crud.put("title", "Sample Model"); + crud.put("body", "http://www.baeldung.com/"); String tagLocation = this.mockMvc.perform(post("/crud").contentType(MediaTypes.HAL_JSON) - .content(this.objectMapper.writeValueAsString(tag))) + .content(this.objectMapper.writeValueAsString(crud))) .andExpect(status().isCreated()) .andReturn() .getResponse() .getHeader("Location"); - Map crud = new HashMap<>(); - crud.put("id", 2L); - crud.put("title", "Sample Model"); - crud.put("body", "http://www.baeldung.com/"); crud.put("tags", singletonList(tagLocation)); this.mockMvc.perform(post("/crud").contentType(MediaTypes.HAL_JSON) diff --git a/spring-5/src/test/java/com/baeldung/restdocs/ApiDocumentationJUnit5IntegrationTest.java b/spring-5/src/test/java/com/baeldung/restdocs/ApiDocumentationJUnit5IntegrationTest.java index d915a4fdde..748d5fb1b3 100644 --- a/spring-5/src/test/java/com/baeldung/restdocs/ApiDocumentationJUnit5IntegrationTest.java +++ b/spring-5/src/test/java/com/baeldung/restdocs/ApiDocumentationJUnit5IntegrationTest.java @@ -7,11 +7,7 @@ import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.li import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; -import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; @@ -72,20 +68,18 @@ public class ApiDocumentationJUnit5IntegrationTest { @Test public void crudGetExample() throws Exception { - Map tag = new HashMap<>(); - tag.put("name", "GET"); + Map crud = new HashMap<>(); + crud.put("id", 1L); + crud.put("title", "Sample Model"); + crud.put("body", "http://www.baeldung.com/"); String tagLocation = this.mockMvc.perform(get("/crud").contentType(MediaTypes.HAL_JSON) - .content(this.objectMapper.writeValueAsString(tag))) + .content(this.objectMapper.writeValueAsString(crud))) .andExpect(status().isOk()) .andReturn() .getResponse() .getHeader("Location"); - Map crud = new HashMap<>(); - crud.put("id", 1L); - crud.put("title", "Sample Model"); - crud.put("body", "http://www.baeldung.com/"); crud.put("tags", singletonList(tagLocation)); ConstraintDescriptions desc = new ConstraintDescriptions(CrudInput.class); @@ -99,20 +93,18 @@ public class ApiDocumentationJUnit5IntegrationTest { @Test public void crudCreateExample() throws Exception { - Map tag = new HashMap<>(); - tag.put("name", "CREATE"); + Map crud = new HashMap<>(); + crud.put("id", 2L); + crud.put("title", "Sample Model"); + crud.put("body", "http://www.baeldung.com/"); String tagLocation = this.mockMvc.perform(post("/crud").contentType(MediaTypes.HAL_JSON) - .content(this.objectMapper.writeValueAsString(tag))) + .content(this.objectMapper.writeValueAsString(crud))) .andExpect(status().isCreated()) .andReturn() .getResponse() .getHeader("Location"); - Map crud = new HashMap<>(); - crud.put("id", 2L); - crud.put("title", "Sample Model"); - crud.put("body", "http://www.baeldung.com/"); crud.put("tags", singletonList(tagLocation)); this.mockMvc.perform(post("/crud").contentType(MediaTypes.HAL_JSON)