diff --git a/rest/headers/README.adoc b/rest/headers/README.adoc new file mode 100644 index 00000000..7e4e3bd3 --- /dev/null +++ b/rest/headers/README.adoc @@ -0,0 +1,43 @@ += Spring Data REST - Headers example + +This example shows how Spring Data REST auto-populates response headers for item resources and considers these values when conditional `GET` requests are used + +== Auto-populated headers + +If entities use optimistic locking (usually by demarcating a particular property as version property using a store-specific annotation), Spring Data REST will use the value stored in that property to populate the `ETag` header for `GET` and `HEAD` requests to the item resource. + +If http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#auditing[Spring Data's auditing capabilities] are activated (using `@EnableJpaAuditing` in this case), the `Last-Modified` header is populated with the value of the last-modified property. See the `Customer` domain class for how to mark those. + +== Conditional GET requests + +The response headers can be used to issue conditional GET requests to save bandwidth in case the resource hasn't changed on the server: + +.Conditional GET using If-Modified-Since +==== +[source,bash] +---- +$ curl http://localhost:8080/customers/1 -i -H "If-Modified-Since: Wed, 08 Apr 2015 17:24:20 GMT" +---- + +[source,http] +---- +HTTP/1.1 304 Not Modified +---- +==== + +.Conditional GET using If-None-Match +==== +[source,bash] +---- +$ curl http://localhost:8080/customers/1 -i -H "If-None-Match: 0" +---- + +[source,http] +---- +HTTP/1.1 304 Not Modified +---- +==== + +== Spring RESTDocs + +The sample uses https://github.com/wilkinsona/spring-restdocs[Spring RESTDocs] to document the HTTP interaction implemented using the test cases. See `WebIntegrationTests.setUp()` for general setup and the individual test methods with their usage of `….andDo(document(…))`. \ No newline at end of file diff --git a/rest/headers/pom.xml b/rest/headers/pom.xml index 3f64a84e..44a5c17d 100644 --- a/rest/headers/pom.xml +++ b/rest/headers/pom.xml @@ -11,7 +11,7 @@ spring-data-rest-examples 1.0.0.BUILD-SNAPSHOT - + Gosling-BUILD-SNAPSHOT @@ -22,7 +22,7 @@ org.springframework.boot spring-boot-starter-data-jpa - + com.fasterxml.jackson.datatype jackson-datatype-jsr310 @@ -33,6 +33,13 @@ hsqldb + + org.springframework.restdocs + spring-restdocs + 0.1.0.BUILD-SNAPSHOT + test + + \ No newline at end of file diff --git a/rest/headers/src/test/java/example/orders/WebIntegrationTests.java b/rest/headers/src/test/java/example/orders/WebIntegrationTests.java index 157dfe5b..ae2ee74f 100644 --- a/rest/headers/src/test/java/example/orders/WebIntegrationTests.java +++ b/rest/headers/src/test/java/example/orders/WebIntegrationTests.java @@ -16,6 +16,7 @@ package example.orders; import static org.springframework.http.HttpHeaders.*; +import static org.springframework.restdocs.RestDocumentation.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @@ -28,6 +29,7 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.restdocs.config.RestDocumentationConfigurer; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; @@ -51,7 +53,10 @@ public class WebIntegrationTests { @Before public void setUp() { - this.mvc = MockMvcBuilders.webAppContextSetup(context).build(); + + this.mvc = MockMvcBuilders.webAppContextSetup(context).// + apply(new RestDocumentationConfigurer()).// + build(); } @Test @@ -67,11 +72,13 @@ public class WebIntegrationTests { // ETag-based mvc.perform(get(uri).header(IF_NONE_MATCH, response.getHeader(ETAG))).// - andExpect(status().isNotModified()); + andExpect(status().isNotModified()).// + andDo(document("if-none-match")); // Last-modified-based mvc.perform(get(uri).header(IF_MODIFIED_SINCE, response.getHeader(LAST_MODIFIED))).// - andExpect(status().isNotModified()); + andExpect(status().isNotModified()).// + andDo(document("if-modified-since")); } } diff --git a/rest/headers/src/test/resources/documentation.properties b/rest/headers/src/test/resources/documentation.properties new file mode 100644 index 00000000..bdb0fef8 --- /dev/null +++ b/rest/headers/src/test/resources/documentation.properties @@ -0,0 +1 @@ +org.springframework.restdocs.outputDir=target/generated-snippets \ No newline at end of file