From 3715a72b46a76b57beb83712adb0f101f8a3b974 Mon Sep 17 00:00:00 2001 From: selva Date: Tue, 2 Jul 2019 19:30:32 +0100 Subject: [PATCH 1/2] spring rest docs --- pom.xml | 26 +++ src/main/asciidoc/index.adoc | 161 ++++++++++++++++++ ...opertyRegistryServiceApplicationTests.java | 31 +++- 3 files changed, 215 insertions(+), 3 deletions(-) create mode 100644 src/main/asciidoc/index.adoc diff --git a/pom.xml b/pom.xml index 560a63c..6eaaf23 100644 --- a/pom.xml +++ b/pom.xml @@ -105,6 +105,12 @@ springfox-bean-validators 2.8.0 + + org.springframework.restdocs + spring-restdocs-mockmvc + test + + @@ -136,6 +142,26 @@ + + org.asciidoctor + asciidoctor-maven-plugin + + + generate-docs + prepare-package + + process-asciidoc + + + index.adoc + html + + ${project.build.directory}/generated-snippets/ + + + + + diff --git a/src/main/asciidoc/index.adoc b/src/main/asciidoc/index.adoc new file mode 100644 index 0000000..c4cbf2b --- /dev/null +++ b/src/main/asciidoc/index.adoc @@ -0,0 +1,161 @@ += Getting Started With Spring REST Docs + +This is an example output for the registry service + +:snippets: ../../../target/generated-snippets + +=== Create Entity using POST Requests + +==== Phenotype + +.request + +include::{snippets}/should-create-phenotype/1/http-request.adoc[] + +.response + +include::{snippets}/should-create-phenotype/1/http-response.adoc[] + + +==== Property +.request + +include::{snippets}/should-create-property/1/http-request.adoc[] + +.response + +include::{snippets}/should-create-property/1/http-response.adoc[] + + +== Query Entity using GET Requests + +==== Phenotype +.request + +include::{snippets}/should-query-phenotype/1/http-request.adoc[] + +.response + +include::{snippets}/should-query-phenotype/1/http-response.adoc[] + +==== Property +.request + +include::{snippets}/should-query-properties/1/http-request.adoc[] + +.response + +include::{snippets}/should-query-properties/1/http-response.adoc[] + +== Update Entity using PATCH/PUT Requests + +==== Phenotype +.request + +include::{snippets}/should-update-phenotype/2/http-request.adoc[] + +.response + +include::{snippets}/should-update-phenotype/2/http-response.adoc[] + +==== Property +.request + +include::{snippets}/should-update-property/2/http-request.adoc[] + +.response +include::{snippets}/should-update-property/2/http-response.adoc[] + +== Partial update Entity using PATCH/PUT Requests + +==== Phenotype +.request + +include::{snippets}/should-partially-update-phenotype/2/http-request.adoc[] + +.response + +include::{snippets}/should-partially-update-phenotype/2/http-response.adoc[] + +==== Property +.request + +include::{snippets}/should-partially-update-property/2/http-request.adoc[] + +.response +include::{snippets}/should-partially-update-property/2/http-response.adoc[] + +== Delete Entity using DELETE Requests + +==== Phenotype +.request + +include::{snippets}/should-delete-phenotype/2/http-request.adoc[] + +.response + +include::{snippets}/should-delete-phenotype/2/http-response.adoc[] + +==== Property +.request + +include::{snippets}/should-delete-property/2/http-request.adoc[] + +.response +include::{snippets}/should-delete-property/2/http-response.adoc[] + +== Test Authorization + +==== Accessing secured endpoints without authentication +.request + +include::{snippets}/test-authorization/1/http-request.adoc[] + +.response + +include::{snippets}/test-authorization/1/http-response.adoc[] + +==== Accessing secured endpoints with authentication token +===== User with ROLE_READ +.request + +include::{snippets}/test-authorization/11/http-request.adoc[] + +.response + +include::{snippets}/test-authorization/11/http-response.adoc[] + +.request + +include::{snippets}/test-authorization/14/http-request.adoc[] + +.response + +include::{snippets}/test-authorization/14/http-response.adoc[] + +===== User with ROLE_EDITOR + +.request + +include::{snippets}/test-authorization/15/http-request.adoc[] + +.response + +include::{snippets}/test-authorization/15/http-response.adoc[] + +.request + +include::{snippets}/test-authorization/19/http-request.adoc[] + +.response + +include::{snippets}/test-authorization/19/http-response.adoc[] + +===== User with ROLE_ADMIN +.request + +include::{snippets}/test-authorization/20/http-request.adoc[] + +.response + +include::{snippets}/test-authorization/20/http-response.adoc[] diff --git a/src/test/java/uk/ac/ebi/ampt2d/registry/PropertyRegistryServiceApplicationTests.java b/src/test/java/uk/ac/ebi/ampt2d/registry/PropertyRegistryServiceApplicationTests.java index 8808130..11f46d2 100644 --- a/src/test/java/uk/ac/ebi/ampt2d/registry/PropertyRegistryServiceApplicationTests.java +++ b/src/test/java/uk/ac/ebi/ampt2d/registry/PropertyRegistryServiceApplicationTests.java @@ -18,26 +18,37 @@ package uk.ac.ebi.ampt2d.registry; 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.autoconfigure.json.AutoConfigureJsonTesters; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.restdocs.JUnitRestDocumentation; +import org.springframework.security.web.FilterChainProxy; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; import uk.ac.ebi.ampt2d.registry.entities.Phenotype; import uk.ac.ebi.ampt2d.registry.entities.Property; import uk.ac.ebi.ampt2d.registry.repositories.PhenotypeRepository; import uk.ac.ebi.ampt2d.registry.repositories.PropertyRepository; import uk.ac.ebi.ampt2d.registry.service.mail.MailService; +import javax.annotation.Resource; + import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doNothing; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; +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.annotation.DirtiesContext.ClassMode.AFTER_CLASS; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -49,12 +60,13 @@ @RunWith(SpringRunner.class) @SpringBootTest(properties = {"security.enabled=true", "spring.jpa.hibernate.ddl-auto=none"}) -@AutoConfigureMockMvc @AutoConfigureJsonTesters @DirtiesContext(classMode = AFTER_CLASS) public class PropertyRegistryServiceApplicationTests { - @Autowired + @Rule + public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("target/generated-snippets"); + private MockMvc mockMvc; @Autowired @@ -75,11 +87,24 @@ public class PropertyRegistryServiceApplicationTests { @MockBean private MailService mailService; + @Autowired + private WebApplicationContext webApplicationContext; + + @Resource + private FilterChainProxy springSecurityFilterChain; + @Before public void setUp() throws Exception { doNothing().when(mailService).send(anyString()); phenotypeRepository.deleteAll(); propertyRepository.deleteAll(); + mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).apply + (documentationConfiguration(restDocumentation)) + .alwaysDo(document("{method-name}/{step}" + , preprocessRequest(prettyPrint()) + , preprocessResponse(prettyPrint()))) + .addFilters(springSecurityFilterChain) + .build(); } @Test From 0b8fb0f3cfc62387197db62468aef5e62470469f Mon Sep 17 00:00:00 2001 From: selvaebi Date: Tue, 30 Jul 2019 11:01:57 +0100 Subject: [PATCH 2/2] requestField descriptions --- src/main/asciidoc/index.adoc | 9 +++++ ...opertyRegistryServiceApplicationTests.java | 34 ++++++++++++++++--- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/main/asciidoc/index.adoc b/src/main/asciidoc/index.adoc index c4cbf2b..318417e 100644 --- a/src/main/asciidoc/index.adoc +++ b/src/main/asciidoc/index.adoc @@ -8,6 +8,10 @@ This is an example output for the registry service ==== Phenotype +.requestFields + +include::{snippets}/should-create-phenotype/1/request-fields.adoc[] + .request include::{snippets}/should-create-phenotype/1/http-request.adoc[] @@ -18,6 +22,11 @@ include::{snippets}/should-create-phenotype/1/http-response.adoc[] ==== Property + +.requestFields + +include::{snippets}/should-create-property/1/request-fields.adoc[] + .request include::{snippets}/should-create-property/1/http-request.adoc[] diff --git a/src/test/java/uk/ac/ebi/ampt2d/registry/PropertyRegistryServiceApplicationTests.java b/src/test/java/uk/ac/ebi/ampt2d/registry/PropertyRegistryServiceApplicationTests.java index 11f46d2..38c9eeb 100644 --- a/src/test/java/uk/ac/ebi/ampt2d/registry/PropertyRegistryServiceApplicationTests.java +++ b/src/test/java/uk/ac/ebi/ampt2d/registry/PropertyRegistryServiceApplicationTests.java @@ -49,6 +49,8 @@ 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.test.annotation.DirtiesContext.ClassMode.AFTER_CLASS; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -115,10 +117,32 @@ public void shouldReturnRepositoryIndex() throws Exception { jsonPath("$._links.phenotypes").exists()); } - private String postTestEntity(String uri, String content) throws Exception { + private String postTestPhenotypeEntity(String uri, String content) throws Exception { MvcResult mvcResult = mockMvc.perform(post(uri).with(oAuthHelper.bearerToken("testEditor@gmail.com")).content (content)) .andExpect(status().isCreated()) + .andDo(document("{method-name}/{step}", requestFields( + fieldWithPath("id").description("Unique identifier of a Phenotype"), + fieldWithPath("description").description("Description of a Phenotype"), + fieldWithPath("type").description("CONTINUOUS/DICHOTOMOUS/TRICHOTOMOUS"), + fieldWithPath("phenotypeGroup").description("Example values: ANTHROPOMETRIC,RENAL.."), + fieldWithPath("allowedValues").description("Format of values eg : nn.nn / 0 or 1") + ))) + .andReturn(); + + return mvcResult.getResponse().getHeader("Location"); + } + + private String postTestPropertyEntity(String uri, String content) throws Exception { + MvcResult mvcResult = mockMvc.perform(post(uri).with(oAuthHelper.bearerToken("testEditor@gmail.com")).content + (content)) + .andExpect(status().isCreated()) + .andDo(document("{method-name}/{step}", requestFields( + fieldWithPath("id").description("Unique identifier of a Property"), + fieldWithPath("description").description("Description of a Property"), + fieldWithPath("type").description("Example values: DOUBLE,INTEGER.."), + fieldWithPath("meaning").description("meaning related to portal") + ))) .andReturn(); return mvcResult.getResponse().getHeader("Location"); @@ -127,7 +151,7 @@ private String postTestEntity(String uri, String content) throws Exception { private String postTestPhenotype() throws Exception { Phenotype phenotype = new Phenotype("BMI", Phenotype.Group.ANTHROPOMETRIC, "Body Mass Index", Phenotype.Type.CONTINUOUS, "nn.nn"); - return postTestEntity("/phenotypes", phenotypeJacksonTester.write(phenotype).getJson()); + return postTestPhenotypeEntity("/phenotypes", phenotypeJacksonTester.write(phenotype).getJson()); } @Test @@ -199,7 +223,7 @@ public void shouldDeletePhenotype() throws Exception { private String postTestProperty() throws Exception { Property property = new Property("CALL_RATE", Property.Type.FLOAT, Property.Meaning.CALL_RATE, "calling rate"); - return postTestEntity("/properties", propertyJacksonTester.write(property).getJson()); + return postTestPropertyEntity("/properties", propertyJacksonTester.write(property).getJson()); } @Test @@ -281,9 +305,9 @@ public void testPaging() throws Exception { Property property1 = new Property("CALL_RATE", Property.Type.DOUBLE, Property.Meaning.CALL_RATE, "calling rate"); Property property2 = new Property("MAF", Property.Type.FLOAT, Property.Meaning.MAF, "MAF"); - postTestEntity("/properties", propertyJacksonTester.write(property1).getJson()); + postTestPropertyEntity("/properties", propertyJacksonTester.write(property1).getJson()); - postTestEntity("/properties", propertyJacksonTester.write(property2).getJson()); + postTestPropertyEntity("/properties", propertyJacksonTester.write(property2).getJson()); mockMvc.perform(get("/properties?size=1").with(oAuthHelper.bearerToken("testUser@gmail.com"))) .andExpect(status().isOk())