further HATEOAS work

This commit is contained in:
eugenp 2014-01-05 19:35:19 +02:00
parent 00ef9f688c
commit 71122adb3e
7 changed files with 87 additions and 3 deletions

View File

@ -6,6 +6,8 @@
### Relevant Articles: ### Relevant Articles:
- [Spring Security Expressions - hasRole Example](http://www.baeldung.com/spring-security-expressions-basic) - [Spring Security Expressions - hasRole Example](http://www.baeldung.com/spring-security-expressions-basic)
- [REST Pagination in Spring](http://www.baeldung.com/2012/01/18/rest-pagination-in-spring/) - [REST Pagination in Spring](http://www.baeldung.com/2012/01/18/rest-pagination-in-spring/)
- [HATEOAS for a Spring REST Service](http://www.baeldung.com/2011/11/13/rest-service-discoverability-with-spring-part-5/)
- [REST API Discoverability and HATEOAS](2011/11/06/restful-web-service-discoverability-part-4/)
### Build the Project ### Build the Project

View File

@ -48,8 +48,9 @@ public class FooController {
@RequestMapping(value = "/{id}", method = RequestMethod.GET) @RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody @ResponseBody
public Foo findOne(@PathVariable("id") final Long id, final UriComponentsBuilder uriBuilder, final HttpServletRequest request, final HttpServletResponse response) { public Foo findById(@PathVariable("id") final Long id, final HttpServletRequest request, final HttpServletResponse response) {
final Foo resourceById = RestPreconditions.checkFound(service.findOne(id)); final Foo resourceById = RestPreconditions.checkFound(service.findOne(id));
eventPublisher.publishEvent(new SingleResourceRetrieved(this, request, response)); eventPublisher.publishEvent(new SingleResourceRetrieved(this, request, response));
return resourceById; return resourceById;
} }

View File

@ -0,0 +1,33 @@
package org.baeldung.web.hateoas;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.ApplicationEvent;
public class ResourceCreated extends ApplicationEvent {
private final HttpServletResponse response;
private final HttpServletRequest request;
private final long idOfNewResource;
public ResourceCreated(final Object source, final HttpServletRequest request, final HttpServletResponse response, final long idOfNewResource) {
super(source);
this.request = request;
this.response = response;
this.idOfNewResource = idOfNewResource;
}
public HttpServletResponse getResponse() {
return response;
}
public HttpServletRequest getRequest() {
return request;
}
public long getIdOfNewResource() {
return idOfNewResource;
}
}

View File

@ -0,0 +1,26 @@
package org.baeldung.web.hateoas;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.ApplicationEvent;
public class SingleResourceRetrieved extends ApplicationEvent {
private final HttpServletResponse response;
private final HttpServletRequest request;
public SingleResourceRetrieved(final Object source, final HttpServletRequest request, final HttpServletResponse response) {
super(source);
this.request = request;
this.response = response;
}
public HttpServletResponse getResponse() {
return response;
}
public HttpServletRequest getRequest() {
return request;
}
}

View File

@ -7,6 +7,7 @@ import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.net.HttpHeaders;
@Component @Component
class SingleResourceRetrievedDiscoverabilityListener implements ApplicationListener<SingleResourceRetrieved> { class SingleResourceRetrievedDiscoverabilityListener implements ApplicationListener<SingleResourceRetrieved> {
@ -26,7 +27,7 @@ class SingleResourceRetrievedDiscoverabilityListener implements ApplicationListe
final String uriForResourceCreation = requestURL.substring(0, positionOfLastSlash); final String uriForResourceCreation = requestURL.substring(0, positionOfLastSlash);
final String linkHeaderValue = LinkUtil.createLinkHeader(uriForResourceCreation, "collection"); final String linkHeaderValue = LinkUtil.createLinkHeader(uriForResourceCreation, "collection");
response.addHeader("Link", linkHeaderValue); response.addHeader(HttpHeaders.LINK, linkHeaderValue);
} }
} }

View File

@ -2,6 +2,7 @@ package org.baeldung.common.web;
import static org.apache.commons.lang3.RandomStringUtils.randomNumeric; import static org.apache.commons.lang3.RandomStringUtils.randomNumeric;
import static org.baeldung.web.util.HTTPLinkHeaderUtil.extractURIByRel; import static org.baeldung.web.util.HTTPLinkHeaderUtil.extractURIByRel;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
@ -12,6 +13,7 @@ import java.io.Serializable;
import java.util.List; import java.util.List;
import org.baeldung.test.IMarshaller; import org.baeldung.test.IMarshaller;
import org.hamcrest.core.AnyOf;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -36,6 +38,18 @@ public abstract class AbstractLiveTest<T extends Serializable> {
} }
// tests // tests
@Test
public void whenInvalidPOSTIsSentToValidURIOfResource_thenAllowHeaderListsTheAllowedActions() {
// Given
final String uriOfExistingResource = createAsUri();
// When
final Response res = givenAuth().post(uriOfExistingResource);
// Then
final String allowHeader = res.getHeader(HttpHeaders.ALLOW);
assertThat(allowHeader, AnyOf.<String> anyOf(containsString("GET"), containsString("PUT"), containsString("DELETE")));
}
// find - one // find - one
@ -111,11 +125,13 @@ public abstract class AbstractLiveTest<T extends Serializable> {
public abstract void create(); public abstract void create();
public abstract String createAsUri();
protected final void create(final T resource) { protected final void create(final T resource) {
createAsUri(resource); createAsUri(resource);
} }
final String createAsUri(final T resource) { protected final String createAsUri(final T resource) {
final Response response = createAsResponse(resource); final Response response = createAsResponse(resource);
Preconditions.checkState(response.getStatusCode() == 201, "create operation: " + response.getStatusCode()); Preconditions.checkState(response.getStatusCode() == 201, "create operation: " + response.getStatusCode());

View File

@ -25,4 +25,9 @@ public class FooLiveTest extends AbstractLiveTest<Foo> {
create(new Foo(randomAlphabetic(6))); create(new Foo(randomAlphabetic(6)));
} }
@Override
public final String createAsUri() {
return createAsUri(new Foo(randomAlphabetic(6)));
}
} }