Creating Links Using Spring Boot HATEOAS

So I am involved in this project currently where the project architect suggested that we follow HATEOAS-driven RESTful web service. This is probably something I have read about before, but didn’t really pay much attention to, or I simply forgot.

Learning something new is always fun. Well, most of the time it is. It depends upon the context. But for this one, I’m always eager and curious to know how things work.

Everything is going along fine locally. We were able to build the links to the objects. The implementation was working as we hoped. We deployed it to Red Hat OpenShift successfully. And everybody was just as happy as a clam.

Then I noticed something weird.

You see, one of the purpose of the links is that when your web service returns something from, say a GET API endpoint with a lot of relationships to other entities, those other entities included within the response with links should work when you click on it.

I clicked on one of the links and got surprised when nothing came back. I repeatedly clicked on it many times, but got the same result each time. Weird. I was pretty sure the resource was created and exists. The GET request should have worked.

Checking on the database. Sure enough I could see the record in the table. So why was the link giving me this weird error?

Then I started to realize. Even if the ID does not exist, the error should have been 404 with a formatted message. Because that’s what the app should have done. But it wasn’t.

Looking at the screen intently. It was actually that familiar error you see on Postman app when the web service is not yet running. But being that it was deployed on the server, with all the build processes in lovely green check marks, it should have already started.

I looked at the URL one more time. Then I saw that it was HTTP instead of HTTPS.

Whoa! What is going on?!

Further reading told me that this should have not happened if the proxy server was configured properly or with the additional forwarding configuration. There should have been a Request Header that would have told the link builder what scheme to use. Something like the below if you are using Apache2 web server.

RequestHeader set X-Forwarded-Proto "https"

My guess is that the above directive may not be in the server’s configuration.

So, in some method in some Controller class I was using this line of code that follows below to create a very simple GET link after a successful POST. It works quite well, until it doesn’t because our application is sitting inside an OpenShift container and it is sitting behind a proxy server/firewall/load balancer.

String link = linkTo(this.getClass()).slash(entityId).withSelfRel().getHref();

That will output something like so:

http://localhost:8080/contextpath/something/69

What to do?

Luckily, the ControllerLinkBuilder class is built around the UriComponentBuilder. With a little research, I found out later on that just like its older cousin, you can manipulate the URI to a specific scheme. I’ve been using that trick already a while back.

Now to solve this issue, because I want to have it return a link using HTTPS, then the following will force the link to do so.

String link = new Link(linkTo(this.getClass()).slash(entityId).toUriComponentsBuilder().scheme("https").build().toUriString()).withSelfRel().getHref();

And the output is now. Ta dah!

https://localhost:8080/contextpath/something/69

Of course, if you are testing if the links are working locally, you would not want to be in this situation, right? And it would be too inconvenient to keep on changing that one line of code. You can, of course, be creative and do something. Like perhaps use the Spring Boot way of determining if the app is running on DEV or TEST or PROD profiles is what comes to mind. It is easy. I’ll write about it in another post.

The following link is a good resource to read for Spring Boot HATEOAS

https://docs.spring.io/spring-hateoas/docs/1.1.0.RELEASE/reference/html/

Also, know that WebMvcLinkBuilder will replace ControllerLinkBuilder because the latter is being deprecated. But I didn’t know that before. Now I do.

Note: Pardon the letter case of everything here. I have configured this blog to force everything to lowercase. Something I should not have done but it forces my posts to be uniform regardless of when I wrote it and in what state of mind I was in. Probably a bad idea, but I’ll leave it this way for now.

Similar Posts: