I am using spring boot version 2.0.6
which comes with HATEOAS version 0.25
. I am using a resource assembler that utlises ControllerLinkBuilder
to generate resource links. However, the problem is it generates relative links, how to configure it to use a host
and port
scheme from either request headers (the app will run as a docker container in dev, qa and prod) or config properties when running it locally from IDE.
I get link that respects X-Forwarded-Host
header
"_links": {
"self": {
"href": "http://something.io/data/api/customers"
}
}
if I explicitly add header X-Forwarded-Host
and generate the self link with this code
Link self = new Link(
ServletUriComponentsBuilder.fromRequestUri(request).buildAndExpand(pageable).toUri().toString(),
"self");
But when in resource assembler I rely on the usual linkTo
calls from ControllerLinkBuilder
the host and port are not rendered in the link.
"_links": {
"self": {
"href": "/customers/1"
},
"customers": {
"href": "/customers"
},
"contact": {
"href": "/customers/1/contact"
}
}
The controller definition
@Slf4j
@RestController
@RequestMapping("/customers")
@ExposesResourceFor(Customer.class)
public class CustomerController {
}
and the get method
@GetMapping(produces = MediaTypes.HAL_JSON_VALUE)
public DeferredResult<ResponseEntity<Resources<Resource<Customer>>>> getAllCustomers(
@PageableDefault(page = 0, size = 20, sort = "name", direction = Direction.ASC) Pageable pageable,
PagedResourcesAssembler<Customer> assembler, HttpServletRequest request) {
}
I'm passing request object here because linkTo
gives a url without host and port
And I'm using a Customer Resource assembler from the code here, spring hateoas exmaples which is autowired to this controller
@Autowired
private CustomerResourceAssember customerResourceAssembler;
and this is how I call paged resource assembler
assembler.toResource(result, customerResourceAssembler, self)
The UriComponentsBuilder
in spring-hateoas calls RequestContextHolder.getRequestAttributes()
to get the request attributes. These are attached to the thread by the dispatcher servlet. As you're using DeferredResult, you will already have returned the thread with the request attributes. The thread being used to build the links doesn't have any request attributes on it. This results in relative paths being used.
There are a couple of issues about it already, but they don't suggest that there is anyway you can use any properties to set the base url. Which seems a shame.
There are a few simlar questions, the answers seem to suggest you need to pass the request details to the new thread. Here's a couple in case you haven't found them already.