Spring HATEOAS: "links" vs "_links" and JSON formats

Posted by Steven

Recently, I added Spring HATEOAS to the IT Hub. Refactoring the controller to return RepresentationModel and CollectionModel, I noticed something odd. When returning a collection of items, in the returned JSON, the links for each item were represented under "links". When returning a single item, the links for this item were represented under "_links". This article briefly explains the reasons for this and how to fix it.

Researching the issue, I realized two things. First, my Spring configuration was missing something crucial. Spring HATEOAS works, but it has to be configured correctly. I learned that there's a difference between returning JSON and something called HAL-JSON. Returning a link-collection in plain JSON will result in the links being in "links", while in HAL-JSON, they are in "_links". HAL is the "Hypertext Application Language" and is one of many representation of resources. There is also "collection + json", Hydra  and Siren. Spring has to be configured to return all resource-representations in the same format.

The second problem was the returned class in the controller method. The endpoint for multiple items returned a java.util.list of these objects. The controller method for only one item did the right thing: returning a RepresentationModel.

After fixing both issues, this is the working code (the important parts):

  1. @RestController
  2. @RequestMapping("/api/groups")
  3. public class GroupController {
  5. private final GroupRepository groupRepository;
  7. @Autowired
  8. public GroupController(GroupRepository groupRepository) {
  9. this.groupRepository = groupRepository;
  10. }
  12. @GetMapping(value = "")
  13. public ResponseEntity<CollectionModel<GroupModel>> getAllGroups() {
  15. List<GroupModel> groupModels = groupRepository
  16. .findAllByOrderByNameAsc()
  17. .stream()
  18. .map((group) -> new GroupResourceAssembler(this.getClass(), GroupModel.class).toModel(group))
  19. .collect(Collectors.toList());
  20. return ResponseEntity.ok(new CollectionModel<>(groupModels));
  21. }
  22. }

Here's the WebConfig to set the returned JSON format to HAL JSON:

  1. @Configuration
  2. @EnableWebMvc
  3. @EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
  4. public class WebConfig implements WebMvcConfigurer {
  6. // ...
  7. }