Spring HATEOAS "links" vs "_links" and JSON Formats

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):

public class GroupController {
    private final GroupRepository groupRepository;
    public GroupController(GroupRepository groupRepository) {
        this.groupRepository = groupRepository;
    @GetMapping(value = "")
    public ResponseEntity<CollectionModel<GroupModel>> getAllGroups() {
        List<GroupModel> groupModels = groupRepository
                .map((group) -> new GroupResourceAssembler(this.getClass(), GroupModel.class).toModel(group))
        return ResponseEntity.ok(new CollectionModel<>(groupModels));

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

@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
public class WebConfig implements WebMvcConfigurer {
	// ...