SPRING HATEOS LINKS (HTTPS vs HTTP) - spring

I have a simple rest service which returns the response when a GET operation is performed along with the HATEOS links. When the service is deployed on the server and is accessed through a load balancer url (Https), the links section contains the url with "http" instead of "https". Any example solution/code for this particular scneario would help me.
For Example:
If a GET operation is performed by using the url(https://servicename.example.com) then I would expect the same url to be in the links section. But I receive something like below.
Response Body:
{
"fieldA": null,
"fieldB": null,
"links": [
{
"rel": "self",
"href": "http://servicename.example.com" // It has to be https
}
]
}
Below is the line of code that adds the links to the Rest Resource that will be exposed to the consumer.
resource.getLinks().add(linkTo(methodOn(ExampleController.class).methodInExampleController(arg a, arg b)).withSelfRel());
The resource that is being exposed to the consumer extends another class"ResourceSupport" where a field called links is declared which is of type List.
Example of Resource class:
imnport com.examplepackage.ResourceSupport
public SampleResource extends ResourceSupport{
private String fieldA,
private String fieldB,
//setters and getters
}
Example of the class where HATEOS Links are declared
import org.springframework.hateoas.Identifiable;
import org.springframework.hateoas.Link;
public ResourceSupport implements Identifiable<Link>{
#JsonInclude(Include.NON_EMPTY)
private final List<Link> links = new ArrayList();
#JsonProperty("links")
public List<Link> getLinks() {
return this.links;
}
}
SPRING HATEOS version: spring-hateos0.24.0.RELEASE

Related

How to customize Spring Data REST to use a custom path for a repository resource?

I'm developing a microservice using SPRING DATA REST where I need to sub-resources to be accessible only thru main resource like the following structure :
http://localhost:8080/posts
http://localhost:8080/posts/1/comments
and block direct access to sub-resource directly like this http://localhost:8080/comments/*.
where comments must be accessible only thru related poste , I did the following in my repository :
#RepositoryRestResource(collectionResourceRel = "posts", path = "posts")
public interface PostRepository extends PagingAndSortingRepository<Post, Long> {
...
}
for comments :
#RepositoryRestResource(collectionResourceRel = "comments", path = "comments")
public interface CommentRepository extends PagingAndSortingRepository<Comment, Long> {
...
}
now by default SPRING DATA REST returns the following results when i goto to : http://localhost:8080
{
"id": 1,
"content": "some post text .........................",
"author":"abc",
"_links": {
"self": {
"href": "http://localhost:8080/posts/1"
},
"attributes": {
"href": "http://localhost:8080/posts/1/comments"
}
}
}
now if i want to post a comment i need to do the following :
http://{server:port}/comment METHOD:POST
{"author":"abc","content":"PQROHSFHFSHOFSHOSF", "post":"http://{server:port}/post/1"}
but what i need to achienve is to POST to an url like this http://{server:port}/posts/1/comment where the POST is the root resource NOT like the previous path http://{server:port}/comment
http://{server:port}/posts/1/comment METHOD:POST
{"author":"abc","content":"PQROHSFHFSHOFSHOSF", "post":"http://{server:port}/post/1"}
i now that this is possible if a create a custom comment #controller but i want to use the already building features of SPRING DATA REST and Hateoas support .

ServletRequestParameter exception, parameter is not present

I am creating an API, using Spring Boot and using PostMan to debug and test the system. Now I am having a difficulty in sending a class object as a parameter.
I wish to send an Entity passed as a parameter and display whether the entity has a specified certification or not.
Currently I am using Postman and using the raw "JSON" format to display my Entity Object, however I am getting an error
"resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required Entity parameter 'store' is not present]"
Can anyone point me in the direction of what the problem could be
My JSON (this is the Entity CLass Object that I created, I am not able to recieve a response from the API, the API should send the string "Passed Check"
{
"id": 1,
"name": "asdasd",
"phoneNumber": "000",
"address": "asdasdasdasdasd",
"latitude": 0.0,
"longitude": 0.0,
"dateAdded": "06/08/2020"
}
Certification Controller
#Controller
public class CertController {
#Autowired
private CertificationRepository certRepo;
#Autowired
private StoreRepository StoreRepository;
#GetMapping(value = "/getCertification")
#GetMapping(value = "/getCertObject")
public #ResponseBody
String getCertificationPOJO(#RequestParam Entity store)
{
return "Passed check";
}
}
Postman Error
In the code you shared, I see a few issues.
Missing Path to Controller
Add #RequestMapping("/cert") on CertController.
#Controller
#RequestMapping("/cert")
public class CertController {
}
Wrong Parameter Type
getCertificationPOJO method should have #RequestBody instead of #RequestParam annotation
#GetMapping(value = "/getCertObject")
public #ResponseBody String getCertificationPOJO(#RequestBody Entity store) {
return "Passed check";
}
You can easily follow this guide: Building a RESTful Web Service

Spring Boot RepositoryRestResource with FeignClient

I have built two spring-boot apps, server side spring-boot micro-service with rest resources and client side spring-boot micro-service app consuming HATEOAS feed using Feign Clients.
I have two entity objects Aggregate and Gateway, on both sides. Gateway is inside Aggregate object
As long as i don't have #RepositoryRestResource interface for Gateway object i can retrieve Gateway object through Aggregate, but if I have the annotation i can't get the Gateway listed on Aggregate object on client side. I have noticed this is because server side HATEOAS feed adds link for Gateway on Aggregate instead of Json structure for Gateway.
Is there anyway i can still get Gateway object from Aggregate object while having a #RepositoryRestResource interface for Gateway object? Or is there a way to configure Feign Client to fill the Gateway object from the link?
Ex..
From Client http://localhost:9999/aggregates/
With #RepositoryRestResource annotation on GatewayRepository
[
{
"id": "a65b4bf7-6ba5-4086-8ca2-783b04322161",
"gateway": null, //<-- Gateway is null here
.......
Without #RepositoryRestResource annotation on GatewayRepository
[
{
"id": "a65b4bf7-6ba5-4086-8ca2-783b04322161",
"gateway": { //<-- Gateway id and properties are there now on Aggregate object
"id": "4a857a7a-2815-454c-a271-65bf56dc6f79",
.......
From Server http://localhost:8000/aggregates/
With #RepositoryRestResource annotation on GatewayRepository
{
"_embedded": {
"aggregates": [
{
"id": "a65b4bf7-6ba5-4086-8ca2-783b04322161",
"_links": {
"self": {
"href": "http://localhost:8000/aggregates/a65b4bf7-6ba5-4086-8ca2-783b04322161"
},
"gateway": { //<-- Gateway becomes a link here
"href": "http://localhost:8000/aggregates/a65b4bf7-6ba5-4086-8ca2-783b04322161/gateway"
},
.......
Without #RepositoryRestResource annotation on GatewayRepository
"_embedded": {
"aggregates": [
{
"id": "b5171138-4313-437a-86f5-f70b2b5fcd22",
"gateway": { //<-- Gateway id and properties are there now on Aggregate object
"id": "3608726b-b1b1-4bd4-b861-ee2bf5c0cc03",
.......
Here are my server side implementation of model objects
#Entity
class Aggregate extends TemplateObject {
#OneToOne(cascade = CascadeType.MERGE)
private Gateway gateway;
.......
}
#Entity
class Gateway extends TemplateObject {
#NotNull
#Column(unique = true)
private String name;
.......
}
And Server side rest repositories are
#RepositoryRestResource
interface GatewayRepository extends JpaRepository<Gateway, String> {
Optional<Gateway> findByName(#Param("name") String name);
}
#RepositoryRestResource
interface AggregateRepository extends JpaRepository<Aggregate, String> {
Optional<Aggregate> findByName(#Param("name") String name);
}
(Using these Rest Resources on port 8000)
On client side i have the same implantation on model dto objects
class Gateway extends TemplateObject {
#NotNull
private String name;
.......
}
class Aggregate extends TemplateObject {
private Gateway gateway;
.......
}
And Feign clients
#FeignClient("billing-service/gateways")
interface GatewayService extends GenericService<Gateway> {
}
#FeignClient("billing-service/aggregates")
interface AggregateService extends GenericService<Aggregate> {
}
(Using these Feign clients on port 9999 client controllers)
Thanks in advance for help, any advice and suggestions is greatly appreciated
You may have a look at using projections along with your rest repositories - have a look here. Afterwards you have only to adapt your FeignClient request paths to provide the respective projection as a parameter.

Spring Data Rest, SpringFox and JpaRepository custom finders

NB: using Spring Boot 1.4.2 + SpringFox 2.6.0
Hi, I'm having an issue with Swagger 2 forms on my API documentation over a #RepositoryRestResource. The code below works fine (REST access OK):
#RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends JpaRepository<Person, Long> {
Person findByLastName(#Param("name") String name);
}
And the HATEOAS links are right too: calling URL /api/people/search
ends up with this (notice parameter "name"):
{
"_links": {
"findByLastName": {
"href": "http://localhost:8080/api/people/search/findByLastName{?name}",
"templated": true
},
"self": {
"href": "http://localhost:8080/api/people/search"
}
}
}
The REST API is ok: URL /api/people/search/findByLastName?name=foobar returns data when executed with a browser
BUT in Swagger the GET parameter type is interpreted as "body" instead of "query" and the form submission (curl ... -d 'foobar'...) fails in 404, attempting to submit "name" as request body.
So I tried to set Swagger explicitly, like this:
#RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends JpaRepository<Person, Long> {
#ApiOperation("Find somebody by it's last name")
#ApiImplicitParams({
#ApiImplicitParam(name = "name", paramType = "query")
})
Person findByLastName(#Param("name") #ApiParam(name = "name") String name);
}
without any success, despite the fact that "name" is well retained in the form as the parameter name in this example :-(
body parameter type on GET query
Does anyone know what could be done to make that Swagger form to work? Thx for your help
This is it : #Param configures Spring Data REST, while #RequestParam fits Swagger
#RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends JpaRepository<Person, Long> {
// #Param Spring Data REST : Use #Param or compile with -parameters on JDK 8
// #RequestParam Swagger : paramType=query cf. $Api*Param
Person findByLastName(#Param("name") #RequestParam("name") String name);
}
Me happy!

spring hateoas generates different responses for collection or pojo

I have two classes
import org.springframework.hateoas.ResourceSupport;
public class A{}
public class B{}
public class AResource extends ResourceSupport {
private final A a;
}
public class BResource extends ResourceSupport {
private final B b;
}
#Controller
public class Controller {
#RequestMapping
#ResponseBody
public Set<AResource> giveMeColl() {
}
#RequestMapping
#ResponseBody
public BResource giveMeSingle() {
}
}
both responses add links object but for resource A is "links" and for resource B is "_link" and also structure changes
//RESPONSE FOR A
[
{
"content":{
//my fancy object
},
"links":[
{
"rel": "self",
"href": "http://localhost:8080/myid/22"
}
]
}
]
{
"content":{
//my fancy object
},
"_links":[
{
"self": "http://localhost:8080/myid/22/someelse/33"
}]
}
both resources are constructed with assemblers and both are adding the link from the ids
AResource aresource = new AResource(a);
resource.add(linkTo(methodOn(Controller.class).giveMeColl()).withSelfRel());
BResource bresource = new BResource(b);
resource.add(linkTo(methodOn(Controller.class).giveMeSingle()).withSelfRel());
Response headers for a is
"content-type": "application/json;charset=UTF-8"
and for b
"content-type": "application/hal+json;charset=UTF-8"
Could it be because returning an array is not really Restful? as Some post suggest
p.s. I have added and removed #EnableHypermediaSupport but doesn't seem to affect the problem.
"_links" follows the HAL specification. Spring HATEOAS includes a dedicated serializer for that, but it is only used for classes that extend ResourceSupport.
Returning a simple array is not exactly "unRESTful", but it doesn't meet the REST maturity level 3 (Hypermedia controls). In order to achieve that you can wrap the collection into a Resources instance, which extends ResourceSupport. You should get the same link serialization for both types then.

Resources