How to pass generic List<User> to restful web services - java

I have the requirement to create the search operation using restful web services, i.e, using #GET. The method signature takes String and List as input argument and returns List.
public Generic List <Employer> getAllEmployer(String employeeName, Generic List <employeeLocation>);
Kindly request if someone could describe on how to implement the same. Should I use query param or path param or form param. I need to return the List of employer in json format.

if the employee locations are just string, pass them as comma seperated values and spring will take care of converting it to list. I would rather suggest just to have it as a pathparam rather than having it as a query param.

This is just my opinion but I think that the "RESTful" way to pass multiple parameters with the same name would be to a MultiValueMap.
Spring and Jersey both have implementations of MultiValueMap however, below is an example of a spring implementation:
#RequestMapping(method = RequestMethod.GET, value = {"/employer/_search"})
public List<Employer> search(#RequestParam MultiValueMap<String,String> params) {
return someService.search(params);
}
They way that you would call this url would then become:
/employer/_search?employeeName=name&location=1&location=2&location=3
Then behind the scenes spring will create the MultiValueMap for you which is a Map<String,List<String>> where any parameters with the same name are put into the same list.

Related

Having alias param names to accept Url Encoded Form data values

In my Spring web application, I have an API that accepts requests with application/x-www-form-urlencoded content type.
#RequestMapping(value = "/do-it", method = {RequestMethod.POST})
public String test(#ModelAttribute("request")RequestDTO request,HttpServletRequest
httpServletRequest, Map<String, Object> model, RedirectAttributes redirectAttributes){
.....
}
My RequestDTO has following fields in it.
public class RequestDTO {
private String paramOne;
private String paramTwo;
// standard getters and setters
}
This implementation works fine, all the request params get mapped to the request dto as expected. However, now I have this requirement to accept the requests with the fields in following pattern.
param_one, param_two
I understand that, using #JsonProperty annotation on the fields in my request dto is not gonna work in my case since the request is not in the type of application/json.
The only way I have found to solve the issue is creating new setters like following (which looks ugly in my opinion when it comes to naming convention).
public void setParam_one(String param_one) {
this.paramOne = param_one;
}
Can some one help me to find a better way to get this done? I cannot change the param names in original request dto.
Thank you..!
I was able to get this done. Thanks to #neetash for guiding me.
Everything I needed to have was a Custom HandlerMethodArgumentResolver to map the post request body data to the object that I wanted to get.
I followed following linked tutorial to implement it. It contains every single thing someone needs to know to create a HandlerMethodArgumentResolver.
https://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-creating-a-custom-handlermethodargumentresolver/

How to pass list of parameters in rest get call (like filter object in eCommerce )

In my application, there is a requirement of getting data based on some parameters.
I just want to what is the better way to do.
The one way is, I can pass the list of parameters as a path variable.
The second way is, I can pass the request body, I think it is vague and I am not sure it is possible or not.
You can find the code below:
#GetMapping("/cities/{cityName}/latitude/{latitude}/longitude/{longitude}/cityId/{cityId}/street/{street}")
public ResponseEntity<ResponseContainer<CityDto>> getCityByCityNameOrLatitudeAndLongitude() {
}
I just want to know how can I achieve the same.
There is one more question, E-commerce companies have big filter criteria so how they are achieving.
Although there is no hard & fast rule but I generally avoid sending a body in GET request because it's a bad design. You should also refer to this SO Post which contains discussion about using body in GET request. It's an opinionated post and there is no clear YES or NO, but you will get an idea.
HTTP GET with request body
You can either use Path params or query params depending on what those field represent.
Regarding the difference or which to use when I am quoting this answer, which mentions that although there is no hard rule but generally it's better to use params which can uniquely identify the resource as Path param (e.g. id, name etc) and if your param is supposed to do something like filtering/sorting e.g. records after Jan 1 2019 , then go for query param.
Also personally in one of my APIs (which performs filtering), I am using a generic query param, where I pass on JSON object in my query. So basically my API needs to search an object based on variable/multiple attributes. E.g. I have in my db , objects which have certain voltage, current, size etc. values. So, request might come with a combination of 1 or more. So to keep my API flexible, I have provided a query param which can accept JSON object.
So I make a request like this:
{{SERVER}}/api/search?query={voltage:12V,size:10}
And in my API, I can convert this json object to corresponding POJO:
#GET
#Path("/search")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response search(#QueryParam("query") String queryParam) throws Exception
{
Myobj obj = new Gson().fromJson(queryParam, Myobj.class);
// rest of code
By passing the parameters in the path, you are restricting yourself to extend your API. If you want to extend your API, for example, if you want to filter with criteria as Street1 (or) Street2 then your path wouldnot support it and it will force you to update your API. It is better to pass criteria objects in the body or url parameter. Amazon India is passing criteria like below. I have choosen mobiles with criteria as Manufacturer = Samsung or MI, Storage as 8gb or 4gb and they simply appended the criteria in the query parameters.
There is a third way, Request Params.
#GetMapping
public ResponseEntity<ResponseContainer<CityDto>> getCityByCityNameOrLatitudeAndLongitude(#RequestParam("cityName") String cityName, #RequestParam("latitude") String latitude, #RequestParam("longitude") String longitude){
// Your code
}
For more: 16.3.3.3 Binding request parameters to method parameters with #RequestParam
Parameters using this annotation are required by default, but you can specify that a parameter is optional by setting #RequestParam's required attribute to false (e.g., #RequestParam(value="id", required=false)).
https://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#mvc-ann-requestparam

Get multiple values for same parameter name in request URL - Spring boot

In my spring boot application a request comes from the client with the following URL.localhost:8080/api/invoice?invoiceNo=1234&invoiceDate=050218&invoiceNo=6543&invoiceDate=060218
How can I get the values for the request property invoiceNo and invoiceDate. I know we can always use some delimiter while building the URL and fetch it.
I would like to know if there is any springboot way for achieving this.
Any help is much appreciated.
Now when I try request.getParameter("invoiceNo") I get only the first parameter.
use List
public void invoice(#RequestParam(name="invoiceNo") List<String> invoiceNos, #RequestParam(name="invoiceDate") List<String> invoiceDates) {
In spring you can get query parameters by using the annotation #RequestParam inside controller's endpoint method like this:
#GetMapping("/invoice")
public CustomResponse getInvoiceData(
#RequestParam(value="invoiceNo") List<Long> invoiceNoList,
#RequestParam(value="invoiceDate", required = false) List<Date> invoiceDateList){
...
}
You can see another values that this annotation can get (like required, default, etc..) in the docs
As #maruthi mentioned request.getParameterValues("invoiceNumber") is one way. Another way is to add #RequestParam(value="invoiceNo", required=false) List<String> invoiceNo as the controller method parameter.

Can a query parameter name be variable? Like: #QueryParam("//anything")

I have a resource class and within it a #GET that takes one query param called operation (this should be static) and then I want to take a variable number of other query params that can be named anything.
My first thought was to do something like this:
public Response get(
#QueryParam("operation") String operation,
#QueryParam("list") final List<String> list) {
//do stuff
}
The problem here is that I would have to make a request like:
...?operation=logging&list=ABC&list=XYZ
While what I want is to be able to have something like this:
...?operation=logging&anything=ABC&something_else=XYZ
Is there a way to make the list query param #QueryParam(//anything)?
In doing some information gathering I ran across this sort of approach:
#GET
public void gettest(#Context UriInfo ui) {
MultivaluedMap<String, String> queryParams = ui.getQueryParameters();
String operation = queryParams.getFirst("operation");
for (String theKey : queryParams.keySet()) {
System.out.println(queryParams.getFirst(theKey));
//do stuff with each other query param
}
}
Is multivaluedmap the way to go for this situation -- Or is there a way to use a variable query param name? Or a better approach? Thanks.
Edit/Update:
This is using javax.ws.rs
The use case is: this application being used as a tool for mocking responses (used for testing purposes in other applications). The mock responses are retrieved from a DB by looking up the 'operation' and then some sort of 'id'. The actual id used could be any of the "list" query params given. The reason for this is to give flexibility in different applications to use this mock service -- the urls in applications may be constructed many different ways and this makes if so one doesn't have to change around their code to be able to use the mock service.
As in this question, use a map:
#RequestMapping(value = {"/search/", "/search"}, method = RequestMethod.GET)
public String search(
#RequestParam Map<String,String> allRequestParams, ModelMap model) {
return "viewName";
}

Spring, middle score in request parameter

Is there a way to map a query parameter with a middle score using requests in spring?
I have no problem binding single worded parameters doing this:
Uri example: http://localhost:8080/test/?product=hotels
public class CitiesRequest{
private ProductType product;
public ProductType getProduct() {
return this.product;
}
public void setProduct(String product) {
this.product = product;
}
}
But I'd like to be able to receive parameters like this:
http://localhost:8080/test/?product-type=hotels
As Misha stated it is syntactically incorrect to have a variable name with a hyphen in Java. But Spring is fine with that and allows you to specify a parameter name (in the request) different from the variable name (in java code). For exemple, when using RequestMapping driven controller, one can write :
#RequestMapping("/test")
public ModelAndView getProduct(
#RequestParam("product-type") String productType) {
...
}
That way, getProduct will be called for a url like http://localhost/test?product-type=hotels and the parameter productTypewill receive the value hotels. And all is still purely declarative.
By default, Spring maps the query parameter key to the name of the Java variable. However, it's syntactically incorrect to have a variable name with a hyphen in Java, which explains why you're finding it particularly difficult to get Spring to set the parameter's value for you.
One workaround that might work is to just have a Map<String, String[]> parameter to represent all of the parameters. Then Spring doesn't have to map any query parameters to variable names, so the hyphenated name might end up in that map of all parameters. It may not be as comfortable as pre-split parameter objects, but it might get the hyphenated keys.
Another solution might be to configure the WebDataBinder, which controls how data from HTTP requests are mapped onto your controller's request parameters. But that's a whole can of worms, especially if you're just starting out with Spring. You can read more about it in the documentation under "data binding".

Categories