Is there a way to map a Retrofit #QueryMap to some object for a Spring Rest Service? - spring

The client interface looks like this
#GET("v3/users/posts")
Call<User> loadPosts(#QueryMap Map<String,String> data);
The RestController should then process the map of query data returning the user's post. There are multiple parameters that can be put in the map as shown in the UserService.findUserPosts(). Is it possible to use a map to pass data to the Spring Rest controller? The restriction I have is this is inherited from code using #Query parameters but it has now grown to quite a number and a query map would limit the changes on the client. I would be really grateful for some feedback. Many thanks
#RestController
public class UsersController{
#RequestMapping(value = "/user/posts", method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> getUserPosts(.......What here) {
List<Posts> posts = userService.findPostsBy(id,postKey,offset,when);
}

Solved it. For anyone in the future who wants to do what I am doing , simply provide Request parameters for every key pair in the map
i.e #RequestParam("id") String id,
#RequestParam("postKey") Long, #RequestParam("offset") etc.

Related

Spring throw Bad Request if the request param not available in Controller method

I want to restrict the list of allowed request parameters in my controller, so that if I get a request with an undefined parameter in the controller, it should return a bad request, but it returns 200 OK.
I think that this one should be fixed on the framework level, but not in the controller layer.
I am confused about it, and could not find anything on the internet
For e.g I have the following controller definition:
#GetMapping("/Client")
public ResponseEntity<List<Client>> getAllClients(HttpServletRequest httpServletRequest,
#RequestParam(value = McsConstants.PAGE_HEADER, required = false) Integer page,
#RequestParam(value = McsConstants.SIZE_HEADER, required = false) Integer size) {...}
And the valid request would be
GET .../Client
GET .../Client?page=1
GET .../Client?size=10
GET .../Client?page=1&size=10
How can I validate the case when I have an undefined request param like below?
GET .../Client?someUndefinedParam=1
Let me know please for any ideas or links
Thanks!
One way to handle this can be using #RequestParam annotation on a Map or MultiValueMap argument.
The map is populated with all the request parameters, therein you can write your logic to validate and reject unidentified query params.
EDIT: Following is an example for the same-
#RequestMapping(value = "/test", method = RequestMethod.GET)
public void testMethod(#RequestParam Map<String, String> allRequestParams) {
if (!isValidParams(allRequestParams)) {
// isValidParams() will validate the map with a reference map containing all the expected params
// throw BadRequestException here
}
}
Hope this helps!
let me share my knowledge it may helpful for some other scenarios
If the requestparam and variable is same name you no need to mention the value #RequestParam .
below i have mentioned with code example. Please share ur feedback
#GetMapping("/Client")
public ResponseEntity<List<Client>> getAllClients(HttpServletRequest httpServletRequest,
#RequestParam <Optional>Integer page,
#RequestParam <Optional>Integer size) {
//you can do ur logics
}

How to auto generate response fields that do not have POJO

We have a service that simply returns the json document on a GET request. Since we do not have the POJO for the response "model", it appears we won't be able to use the auto response fields generation "goodness".
One option for us is to create the Pojos (quite large, about 50 attributes) and a corresponding controller that uses the pojos. This is awkward as we now have to maintain the model and corresponding controller just so we can auto generate the model.
Any ideas on how we can still leverage some auto generation of the response fields would be greatly appreciated.
Here's the controller I'm referring to:
#RestController
#RequestMapping("/api")
public class ProductController {
#Autowired
ProductService productService;
#RequestMapping(value = { "/products/{ids}" }, method = { RequestMethod.GET },
produces = "application/json", headers={"accept=application/json"})
#Timed
#ExceptionMetered
#LogExecutionTime
public String getProductDetails(#PathVariable("id") String id) {
return productService.getProductDetails(id);
}
At the moment I see no way of leveraging the auto generation without putting additional effort into it. Spring Auto REST Docs works by inspecting POJOs with a Jackson visitor (static introspection without runtime information) and there is currently no way of deriving the JSON fields from a string (would be dynamic at runtime). Thus, I only see two options:
The approach that you already described: Creating the corresponding POJO and using it.
Using Spring REST Docs for the corresponding test and manually document each field in the test. Might be the better option here if you do not want to alter the production code.

Spring RestController url for findById and findByIds

In my Spring Boot application I have a following REST controller:
#RestController
#RequestMapping("/v1.0/decisions")
public class CriterionController {
#Autowired
private CriterionService criterionService;
#RequestMapping(value = "/{decisionId}/criteria/{criterionId}", method = RequestMethod.GET)
public CriterionResponse findById(#PathVariable #NotNull #DecimalMin("0") Long decisionId, #PathVariable #NotNull #DecimalMin("0") Long criterionId) {
Criterion criterion = criterionService.findById(criterionId);
return new CriterionResponse(criterion);
}
}
Everything is working fine and I'm able to retrieve Criterion by its ID.
Right now I need to add additional logic to my CriterionController that will retrieve Criterion by a set of IDs.
Right now I'm in doubt how it can be implemented.. For example should I add a separated endpoint something like:
/{decisionId}/criteria/{criterionIds}
or for example reuse existing one for this purpose or in some other way. Please advise how to implement it according to a best practice of REST.
This is a tricky question, but there are 2 options I can suggest:
/{decisionId}/criteria?id=1&id=2&id=3
or
/{decisionId}/criteria?id=1,2,3
The former could be seen as more RESTful but can end up with a very long URL since you'll be specifying the query parameter each time.
The latter aggregates the ids in a comma separated list. I personally prefer this option and would go for this.
Although not about REST, both URLs are accepted in Section 3.2.8 of RFC 6570

Read query string parameters in Spring REST API (POST)

My Spring REST API is decorated as follows:
In below, I am confused weather, parameters such as list, operation need to be part of Url as query string or do they need to be part of Request Body as form data (Url encoded).
There are situations where I am sending these parameters in query string and it works fine. But couple of my api's are not working properly on production and they work only if I send the data in request body as Url encoded. Can anyone help me explain this behaviour ?
#RequestMapping(value = "/bulkupdate/{companyId}", method = RequestMethod.POST)
#ResponseBody
public ResponseEntity<String> bulkupdateArticle(#RequestParam("list") String documentIdList,
#PathVariable("companyId") String companyId, #RequestParam("operation") String operation){
try{
Looking at the resource I find that it could be better designed in a more REST-ful fashion. I don't like to see POSTed data in the reside in the url.
Next to becoming more Rest-ful it would also make live for you much easier.
I would create a Data Transfer Object and pass it as the body of the POST request to your resource/spring controller.
Going from your data:
public class ArticleToUpdate {
private String list; // list of what ? Maybe design it like List<String> somethingMoreMeaningFull
private String operation;
// .. getters
}
public ResponseEntity<String> bulkupdateArticle(#RequestBody ArticleToUpdate articleToUpdate) {
// .. do whatever you need with the posted data
Now you can post a JSON or XML document in the body which will probably life much easier.
Additionally you could also add validation on the posted data through #Valid support now.

Can we pass multiple JSON objects in a REST url and capture it using Spring #RequestBody?

Is there a better way to pass multiple JSON objects and capture it in #RequestBody in Spring 3? I had referred this, but do not wish to define new wrapper classes for the purpose as explained in that question? Is it Spring's limitation or REST limitation (based on my understanding, this should not be the case)? Desperately need answer, and since I could not post additional comments in same question (was deleted), hence posting it here.
Thanks,
Paddy
for each model use #JsonIgnoreProperties(ignoreUnknown = true)
#RequestMapping(value = "/users/testBean", method = RequestMethod.POST, consumes={"application/json","application/xml"}, produces={"application/json","application/xml"})
public #ResponseBody List<User> testBean(#RequestBody Object object) {
System.out.println("testBean called");
System.out.println(object.toString());
ObjectMapper mapper=new ObjectMapper();
User user =mapper.convertValue(object, User.class);
Tree tree =mapper.convertValue(object, Tree.class);
System.out.println("User:"+user.toString());
System.out.println("Tree:"+tree.toString());
return userService.findAll();
}

Resources