I have a Spring HATEOAS Resource
such that ModelResource extends Resource<Model>
.
In a @RestController
I have a method to create new Model
s:
@RequestMapping(value = "", method = POST)
public ResponseEntity<ModelResource> postModel() {
Model model = service.create().model;
ModelResource resource = assembler.toResource(model);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(URI.create(resource.getLink("self").getHref()));
return new ResponseEntity<>(resource, headers, CREATED);
}
The created ModelResource
returned from the above method is HAL-encoded:
$ curl -v -XPOST localhost:8080/models
> POST /models HTTP/1.1
> User-Agent: curl/7.32.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 201 Created
< Date: Sun, 25 Jan 2015 11:51:50 GMT
< Location: http://localhost:8080/models/0
< Content-Type: application/hal+json; charset=UTF-8
< Transfer-Encoding: chunked
< Server: Jetty(9.2.4.v20141103)
<
{
"id" : 0,
"_links" : {
"self" : {
"href" : "http://localhost:8080/models/0"
}
}
}
In the same controller also have a method to list Model
s.
@RequestMapping(value = "", method = GET)
public List<ModelResource> getModels() {
return service.find().stream()
.map(modelProxy -> assembler.toResource(modelProxy.model))
.collect(Collectors.toList());
}
For some reason, this method returns plain JSON, not HAL:
$ curl -v localhost:8080/models
> GET /models HTTP/1.1
> User-Agent: curl/7.32.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Sun, 25 Jan 2015 11:52:00 GMT
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Server: Jetty(9.2.4.v20141103)
<
[ {
"id" : 0,
"links" : [ {
"rel" : "self",
"href" : "http://localhost:8080/models/0"
} ]
} ]
I've read about @EnableHypermediaSupport
, but I don't have it set anywhere in my code.
From this GitHub issue:
That works as expected. HAL defines the top level resource having to be a document. Thus a plain List by definition cannot be a HAL document. We've restricted the HAL customizations to only be applied if the root object to be rendered is ResourceSupport or a subtype of it to prevent arbitrary objects from getting HAL customizations applied. If you create a ResourceSupport instead of a List, you should see a correct HAL document be rendered.
The HAL Primer provides more detail and examples of what such a top-level wrapping resource looks like. In Spring HATEOAS, you use Resources<T>
to represent such a wrapper, which is itself a Resource<T>
with a self
rel:
@RequestMapping(value = "", method = GET)
public Resources<ModelResource> getModels() {
List<ModelResource> models = service.find().stream()
.map(modelVertex -> assembler.toResource(modelVertex.model))
.collect(Collectors.toList());
return new Resources<>(models, linkTo(methodOn(ModelController.class).getModels()).withRel("self"));
}
The returned Resources<T>
type is then encoded into a document with embedded documents:
$ curl -v localhost:8080/models
> GET /models HTTP/1.1
> User-Agent: curl/7.32.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Sun, 25 Jan 2015 13:53:47 GMT
< Content-Type: application/hal+json; charset=UTF-8
< Transfer-Encoding: chunked
< Server: Jetty(9.2.4.v20141103)
<
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/models"
}
},
"_embedded" : {
"modelList" : [ {
"id" : 0,
"_links" : {
"self" : {
"href" : "http://localhost:8080/models/0"
},
"links" : {
"href" : "http://localhost:8080/models/0/links"
}
}
} ]
}
}
As mentioned above, Resources<T>
extends ResourceSupport
just like Resource<T>
. So you could create a ResourceAssembler
for Resources<ModelResource>
in order to avoid having to creating the self
link by hand, and to generally encapsulate Resource<ModelResource>
creation.
This answer suggests that HAL rendering is enabled by Spring Boot if it is available, which explains resources are being rendered HAL when possible.
I expect Spring is automatically choosing application/hal+json as the default Content-Type for all ResponseEntity instances.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With