Moved al HATEOAS related code from spring-rest-full module to spring-boot-rest
This commit is contained in:
@@ -8,8 +8,6 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring
|
||||
The "Learn Spring Security" Classes: http://github.learnspringsecurity.com
|
||||
|
||||
### Relevant Articles:
|
||||
- [HATEOAS for a Spring REST Service](http://www.baeldung.com/rest-api-discoverability-with-spring)
|
||||
- [REST API Discoverability and HATEOAS](http://www.baeldung.com/restful-web-service-discoverability)
|
||||
- [ETags for REST with Spring](http://www.baeldung.com/etags-for-rest-with-spring)
|
||||
- [Integration Testing with the Maven Cargo plugin](http://www.baeldung.com/integration-testing-with-the-maven-cargo-plugin)
|
||||
- [Introduction to Spring Data JPA](http://www.baeldung.com/the-persistence-layer-with-spring-data-jpa)
|
||||
|
||||
@@ -7,7 +7,6 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import org.baeldung.persistence.model.Foo;
|
||||
import org.baeldung.persistence.service.IFooService;
|
||||
import org.baeldung.web.hateoas.event.ResourceCreatedEvent;
|
||||
import org.baeldung.web.hateoas.event.SingleResourceRetrievedEvent;
|
||||
import org.baeldung.web.util.RestPreconditions;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
@@ -53,7 +52,6 @@ public class FooController {
|
||||
public Foo findById(@PathVariable("id") final Long id, final HttpServletResponse response) {
|
||||
final Foo resourceById = RestPreconditions.checkFound(service.findOne(id));
|
||||
|
||||
eventPublisher.publishEvent(new SingleResourceRetrievedEvent(this, response));
|
||||
return resourceById;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
package org.baeldung.web.controller;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.baeldung.web.metric.IActuatorMetricService;
|
||||
import org.baeldung.web.metric.IMetricService;
|
||||
import org.baeldung.web.util.LinkUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.util.UriTemplate;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = "/auth/")
|
||||
@@ -34,18 +26,6 @@ public class RootController {
|
||||
|
||||
// API
|
||||
|
||||
// discover
|
||||
|
||||
@RequestMapping(value = "admin", method = RequestMethod.GET)
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
public void adminRoot(final HttpServletRequest request, final HttpServletResponse response) {
|
||||
final String rootUri = request.getRequestURL().toString();
|
||||
|
||||
final URI fooUri = new UriTemplate("{rootUri}/{resource}").expand(rootUri, "foo");
|
||||
final String linkToFoo = LinkUtil.createLinkHeader(fooUri.toASCIIString(), "collection");
|
||||
response.addHeader("Link", linkToFoo);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/metric", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Map getMetric() {
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package org.baeldung.web.hateoas.event;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
public class SingleResourceRetrievedEvent extends ApplicationEvent {
|
||||
private final HttpServletResponse response;
|
||||
|
||||
public SingleResourceRetrievedEvent(final Object source, final HttpServletResponse response) {
|
||||
super(source);
|
||||
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
public HttpServletResponse getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package org.baeldung.web.hateoas.listener;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.baeldung.web.hateoas.event.SingleResourceRetrievedEvent;
|
||||
import org.baeldung.web.util.LinkUtil;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.net.HttpHeaders;
|
||||
|
||||
@Component
|
||||
class SingleResourceRetrievedDiscoverabilityListener implements ApplicationListener<SingleResourceRetrievedEvent> {
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(final SingleResourceRetrievedEvent resourceRetrievedEvent) {
|
||||
Preconditions.checkNotNull(resourceRetrievedEvent);
|
||||
|
||||
final HttpServletResponse response = resourceRetrievedEvent.getResponse();
|
||||
addLinkHeaderOnSingleResourceRetrieval(response);
|
||||
}
|
||||
|
||||
void addLinkHeaderOnSingleResourceRetrieval(final HttpServletResponse response) {
|
||||
final String requestURL = ServletUriComponentsBuilder.fromCurrentRequestUri().build().toUri().toASCIIString();
|
||||
final int positionOfLastSlash = requestURL.lastIndexOf("/");
|
||||
final String uriForResourceCreation = requestURL.substring(0, positionOfLastSlash);
|
||||
|
||||
final String linkHeaderValue = LinkUtil.createLinkHeader(uriForResourceCreation, "collection");
|
||||
response.addHeader(HttpHeaders.LINK, linkHeaderValue);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package org.baeldung.common.web;
|
||||
|
||||
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.baeldung.persistence.model.Foo;
|
||||
import org.baeldung.web.util.HTTPLinkHeaderUtil;
|
||||
import org.hamcrest.core.AnyOf;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import com.google.common.net.HttpHeaders;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.response.Response;
|
||||
|
||||
public abstract class AbstractDiscoverabilityLiveTest<T extends Serializable> extends AbstractLiveTest<T> {
|
||||
|
||||
public AbstractDiscoverabilityLiveTest(final Class<T> clazzToSet) {
|
||||
super(clazzToSet);
|
||||
}
|
||||
|
||||
// tests
|
||||
|
||||
// discoverability
|
||||
|
||||
@Test
|
||||
public void whenInvalidPOSTIsSentToValidURIOfResource_thenAllowHeaderListsTheAllowedActions() {
|
||||
// Given
|
||||
final String uriOfExistingResource = createAsUri();
|
||||
|
||||
// When
|
||||
final Response res = RestAssured.post(uriOfExistingResource);
|
||||
|
||||
// Then
|
||||
final String allowHeader = res.getHeader(HttpHeaders.ALLOW);
|
||||
assertThat(allowHeader, AnyOf.anyOf(containsString("GET"), containsString("PUT"), containsString("DELETE")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenResourceIsCreated_thenUriOfTheNewlyCreatedResourceIsDiscoverable() {
|
||||
// When
|
||||
final Foo newResource = new Foo(randomAlphabetic(6));
|
||||
final Response createResp = RestAssured.given()
|
||||
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||
.body(newResource)
|
||||
.post(getURL());
|
||||
final String uriOfNewResource = createResp.getHeader(HttpHeaders.LOCATION);
|
||||
|
||||
// Then
|
||||
final Response response = RestAssured.given()
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||
.get(uriOfNewResource);
|
||||
|
||||
final Foo resourceFromServer = response.body().as(Foo.class);
|
||||
assertThat(newResource, equalTo(resourceFromServer));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenResourceIsRetrieved_thenUriToGetAllResourcesIsDiscoverable() {
|
||||
// Given
|
||||
final String uriOfExistingResource = createAsUri();
|
||||
|
||||
// When
|
||||
final Response getResponse = RestAssured.get(uriOfExistingResource);
|
||||
|
||||
// Then
|
||||
final String uriToAllResources = HTTPLinkHeaderUtil.extractURIByRel(getResponse.getHeader("Link"), "collection");
|
||||
|
||||
final Response getAllResponse = RestAssured.get(uriToAllResources);
|
||||
assertThat(getAllResponse.getStatusCode(), is(200));
|
||||
}
|
||||
|
||||
// template method
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package org.baeldung.web;
|
||||
|
||||
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
|
||||
|
||||
import org.baeldung.common.web.AbstractDiscoverabilityLiveTest;
|
||||
import org.baeldung.persistence.model.Foo;
|
||||
import org.baeldung.spring.ConfigIntegrationTest;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = { ConfigIntegrationTest.class }, loader = AnnotationConfigContextLoader.class)
|
||||
@ActiveProfiles("test")
|
||||
public class FooDiscoverabilityLiveTest extends AbstractDiscoverabilityLiveTest<Foo> {
|
||||
|
||||
public FooDiscoverabilityLiveTest() {
|
||||
super(Foo.class);
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
@Override
|
||||
public final void create() {
|
||||
create(new Foo(randomAlphabetic(6)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String createAsUri() {
|
||||
return createAsUri(new Foo(randomAlphabetic(6)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,8 +6,7 @@ import org.junit.runners.Suite;
|
||||
@RunWith(Suite.class)
|
||||
@Suite.SuiteClasses({
|
||||
// @formatter:off
|
||||
FooDiscoverabilityLiveTest.class
|
||||
,FooLiveTest.class
|
||||
FooLiveTest.class
|
||||
}) //
|
||||
public class LiveTestSuiteLiveTest {
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package org.baeldung.web.util;
|
||||
|
||||
public final class HTTPLinkHeaderUtil {
|
||||
|
||||
private HTTPLinkHeaderUtil() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
public static String extractURIByRel(final String linkHeader, final String rel) {
|
||||
if (linkHeader == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String uriWithSpecifiedRel = null;
|
||||
final String[] links = linkHeader.split(", ");
|
||||
String linkRelation;
|
||||
for (final String link : links) {
|
||||
final int positionOfSeparator = link.indexOf(';');
|
||||
linkRelation = link.substring(positionOfSeparator + 1, link.length()).trim();
|
||||
if (extractTypeOfRelation(linkRelation).equals(rel)) {
|
||||
uriWithSpecifiedRel = link.substring(1, positionOfSeparator - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return uriWithSpecifiedRel;
|
||||
}
|
||||
|
||||
private static Object extractTypeOfRelation(final String linkRelation) {
|
||||
final int positionOfEquals = linkRelation.indexOf('=');
|
||||
return linkRelation.substring(positionOfEquals + 2, linkRelation.length() - 1).trim();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user