Reputation: 8872
Using the @RepositoryRestResource generates paths and injects all the necessary HATEOAS links for a REST API, but when I return the same results from the repository using a controller the JSON structure is different and there are no HATEOAS links.
How would I return get the same JSON structure from a controller as the RepositoryRestResource generated paths?
// /accounts (RepositoryRestResource JSON structure)
{
_embedded: {
accounts: []
},
_links: {
first: {},
self: {},
next: {},
last: {},
profile: {},
search: {}
},
page: {
size: 20,
totalElements: 35,
totalPages: 2,
number: 0
}
}
// /my-accounts (RestController JSON structure)
{
content: [ ... ], // accounts
pageable: {},
totalPages: 1,
totalElements: 2,
last: true,
size: 20,
number: 0,
sort: {},
numberOfElements: 2,
first: true
}
REST Repository:
@RepositoryRestResource(collectionResourceRel = "accounts", path = "accounts", itemResourceRel = "account")
public interface AccountRepository extends PagingAndSortingRepository<Account, Long> {
@RestResource(path = "owner", rel = "owner")
Page<Account> findByOwner(@Param("username") String owner,Pageable p);
}
REST Controller:
@RestController
public class AccountController {
private AccountRepository repo;
@Autowired
public AccountController(AccountRepository repo) {
this.repo = repo;
}
@RequestMapping(
path = "/my-accounts",
method = RequestMethod.GET,
produces = "application/hal+json")
public ResponseEntity<Page<Account>> getStatus(
@RequestParam(value = "page", defaultValue = "0", required = false) int page,
@RequestParam(value = "size", defaultValue = "20", required = false) int size,
Authentication authentication) {
String username = authentication.getName();
Page<Account> accounts = repo.findByOwner(username, PageRequest.of(page, size));
return ResponseEntity.ok(accounts);
}
}
Upvotes: 2
Views: 1093
Reputation: 3758
Basically, Spring Data REST is just a default implementation of a boilerplate code (like controllers) which people usually write exposing Spring Data repositories via REST and using Spring HATEOAS, i.e. trying to reproduce exactly the same effect with your hand-written controller means just writing the whole Spring Data REST on your own, so, it is a bad idea. Luckily, some parts are easy to reproduce though.
If you speak only about adding paging links to your controller's output (and not implementing other things like search controller, to which a link is present in your sample Spring Data REST controller output), you may take a look at how Spring Data REST does it. It uses Spring Data's PagedResourcesAssembler, which accepts a Page
and creates a HATEOAS resource with the required navigation links.
So, to add the paging links, you must inject a PagedResourcesAssembler
instance in your controller and use it:
public ResponseEntity<PagedResources> getStatus(
@RequestParam(value = "page", defaultValue = "0", required = false) int page,
@RequestParam(value = "size", defaultValue = "20", required = false) int size,
Authentication authentication,
PagedResourcesAssembler assembler) {
String username = authentication.getName();
Page<Account> accounts = repo.findByOwner(username, PageRequest.of(page, size));
return ResponseEntity.ok(assembler.toResource(accounts));
}
Upvotes: 1
Reputation: 6331
Not sure, but this might do the trick:
return ResponseEntity.ok(new org.springframework.hateoas.Resource<>(accounts));
If not then you could wrap the accounts in a class that extends ResourceSupport. So just create some class AccountSupport extends ResourceSupport
and add the required links in there. It has a lot of utility methods like
add(linkTo(AccountController.class).withSelfRel());
or for links to individual Accounts:
add(linkTo(AccountController.class).slash(idOfYourAccountInstance).withSelfRel())
Upvotes: 0