Send post request to restcontroller with url to rest repositories - spring-boot

I've 2 entities A and B, where A holds an attribute "b" of class B (a one to one association between A and B)
I want to make a rest call to save an instance of A entity, and passing b param as a url which gives something like that in json:
{
"id": "5",
"b": "/restapi/B/2"
}
/b/2 refers to a findById rest resource of B Repository.
When i execute this targetting rest resource save() of A Repository (usually POST request to url /restapi/A), it works just fine, spring looks for the B entity (2 in this example) by calling the rest resource of B Repository.
I want to perform the same behavior using my own rest controller, by defining a #PostMapping function inside a #RestController component.
Is it possible ?
PS: I already tested sending the above JSON with postman, and the rest api interpreet the "/restapi/B/" as String and tries to deserialize B using a string which abviously fails.

Yes, you can autowire that repository in your restcontroller and just use it from there. You might need a Transactional annotation.
Also I would suggest to take a look at the project Spring-Data-Rest. This provides you already with what you are trying to build. It is an implementation of the HATEOAS principle.

Use #RepositoryRestController in your controller class instead of #RestController

Related

If Service returns DTO not entity, how to handle DTO in other service in Spring Boot?

After reading this article, I change return value of service method entity into DTO.
But I'm little confused in this below situation.
Entity A <- Repository A <- Service A
Entity B <- Repository B <- Service B
Then , If Service B need to access entity A ,so call method in Service A. Since the result of that method is DTO ,not entity, I'm having a hard time dealing with DTO A in Service B.
Should I call repository A in Service B? or should I call Service A in Service B and use modelmapper to covert dto to entity in service B?
// Controller code
#RestController
public FooDTO getSomeFoo(){
return new FooDTO(service.getFoo())
}
// Service code
#Service
public Foo getFoo(){
return repository.find(~)
}
In my opinion, unless you really want to protect your entities to be changed elsewhere other than the corresponding Service, I would avoid DTOs in calls inside the service layer. This means that it is ok to return Entities in methods that you know that are called by other Services in your application, unless you really want to, most probably, over-engineer your application.
Having said that you should return DTOs only in the methods that are called by your Controller layer so that they are used in your REST API (assuming you have one).
Of course, this requires discipline and making sure you don't call methods on your Controller that are supposed to be called only by Services. There is an architecture that tries to tackle this (if you want to read more about it --> https://medium.com/#shivendraodean/software-architecture-the-onion-architecture-1b235bec1dec) and you can try to take advantage of package protected feature to guarantee this.
Should I call repository A in Service B?
Definitely not. You should never (never may be a strong word, but you should at least strive hard to avoid it) do this, otherwise your code will turn into a complete mess without any structure whatsoever.

Where to map RestTemplate ResponseEntity objects to Domain objects

In my Repository, I'm calling external REST API and properly retrieve response which I wrap in ResponseEntity object as below:
ResponseEntity<ExternalModelResponse> response = restTemplate.getForEntity(baseUrl + "/api/externalObject", ExternalModelResponse.class);
However, ExternalModelResponse doesn't follow my Domain model so I want to introduce mapping of the ExternalModelResponse -> Domain model.
What would be the correct place to introduce such mapping? Should:
Repository method already return Domain object? That would imply mapping in the same method which fetched object from external REST API.
Repository method return ExternalModelResponse and let Service handle the mapping?
What is the most common place of such mapping?:
added as toDomainEntity method on ExternalModelResponse?
added as fromExternalModelResponse method on Domain Entity?
added as a method on Repository/Service ?
The service layer should use only domain objects, so I've done this mapping in the controllers.

How to list twice the same GET method in Swagger integrated in Spring Boot

I have a #RestController with a GET method to list all the instances of a Resource R
I want swagger-ui to list thrice this GET method like this:
findRByFoo
findRByBar
findRByFooAndBar
that corresponds to the following GET petitions:
/resources?foo=myFoo
/resources?bar=myBar
/resources?foo=myFoo&bar=myBar
so that the clients of my API Rest don't have to guess that they can search by foo or bar and can simply look at the swagger-ui (version 2.9.2) and use those API calls
However, given that the three methods are at the /resources path, swagger simply lists one of them and only one.
The question is, How may I list the three API calls?
Edit: It seems to be a limitation of Swagger 2 Unable to add multiple operations on same path in swagger rest API documentation #1378, so let me rephrase the question as:
How may I circumvent this limitation?
Does it mean that the design of my API Rest is not as Rest as should be?
I rewrited the RController to have a single GET
#RestController("/path-to-r")
public class RController
{
#GetMapping
public List<R> findR(Optional<String> foo, Optional<String> bar)
{
....
}
}
And added genericModelSubstitutes as explained in Java 8 Optional #RequestParam lost from the swagger-ui #1848
The final result is such that when the clients of my API click in the combo they can see the two optional parameters to include in the GET petition

Iterable object as parameter in spring data rest api

Hi I need to pass a json object in POST request of the SPRING DATA REST. Is it possible to pass directly and make it process with save(iterable) with any Jackson script or we have to use a Controller with #RequestBodyand process the Iterableand save it using repository function??
Now I am doing,
#RequestMapping(value = "batchInsert", method = RequestMethod.POST)
#ResponseBody
public String batchInsert(#RequestBody List<Test> test){
testRepo.save(test);
return "loaded";
}
and implements Serilizable in DAO objectand my doubt whether there is any default format to pass whole json without using any controller as CRUD operates normally. Please help me find solution. Am new to springs and I am unable to use the same url to get request in spring-data-rest API, if I use batchInsertin controller and in rest api. Fortunate to use different api calls now for inserting and searching purpose. Thanks in advance.
Have you tried specifying the consumable media type?
#RequestMapping(value = "batchInsert", method = RequestMethod.POST, consumes="application/json")
It's quite common to pass JSON objects to Spring controllers, so it should work...

Spring boot actuator - Implement custom metrics

I would like to implement custom metric or statistics to my spring boot rest web service using actuator but i am not able to find simple tutorials.
For example:
how to show how many times a certain controller was called and what exact parameter field was filled?
how can i create a metric that when its URL is called, it runs certain query and shows back a json with some result
This seems like a good scenario for AOP (Aspect Oriented Programing) as this will allow you to separate this statistic logic from the business logic.
Have a look at Spring doc for more info about AOP and how to achieve that with Spring.
You can then define a pointcut on your controller and have a service for counting (and probably then storing) the data.
Refer below link
AOP Example
For point two the solution is to create an endpoint class (it can be or not a rest controller class). For example:
#Component
#RestControllerEndpoint(id = "pfm-statistics")
public class StatisticsEndpoint {
#GetMapping(value = "/", produces = "application/vnd.openxmlformats-
officedocument.spreadsheetml.sheet")
#ResponseBody
public byte[] generateStatisticsAsExcel() {
...
Note that the ID is the path to be called from URL. We can create a simple endpoint too and just return a string if we want. In this case instead of #RestControllerEndpoint annotation we can use #Endpoint, as a side note, the id should always contain dash

Resources