How to pass a pageable null from a webService? - java

So I have a backEnd with java and spring boot, the problem is occurring in pageable of the following code from a webservice:
#GetMapping(produces = MediaType.APPLICATION_JSON)
public Page<AreaDto> search(
#RequestParam(value = "name", required = false) String name,
#RequestParam(value = "codOrg", required = false) Long codOrg,
#RequestParam(value = "codCar", required = false) Long codCar,
Pageable pageable
) {
...
...
but if I do not pass the pageable as parameter or pass with the itens ​​of the pageable all set to null it always comes with default values, which are as follows:
.
Page request [number: 0, size 20, sort: null]
.
for example, if I call this webservice in any of the ways below, the pageable will always come mounted with default values
resources/areas?page=null&size=null&sort=null
resources/areas?page=0&size=0
resources/areas
resources/areas?name='test'
So that's it, how to call this webservice with a pageable null?

What about implementing your own PageableHandlerMethodArgumentResolverCustomizer? If no arguments are provided, just return null?

Related

Java Spring Boot: Swagger GET List in the Request

I am trying to setup a GET request in Java Spring Boot Swagger, with a list of ProductIds in the request. How can I edit the code below for this?
#GET
#Path("/product/{customerId}/{productIds}")
#ApiOperation(
value = "Get Products",
response = ProductResponse.class,
responseContainer = "List"
)
List<ProductResponse> getProductData(
#ApiParam(value = "customerId", required = true) #PathParam("customerId") long customerId,
#ApiParam(value = "productIds", required = true) #PathParam("productIds") List<Long> productIds
);
Result: with CustomerId 7 and ProductIds (2,3)
404 Not Found
http://localhost:50111/product-domain/api/product/7/2%2C3
Update: if I use RequestParam for ProductIds, how would I input this in swagger body? Note: any solution will work, (don't necessarily need to use RequestParam)
#RequestParam(value="productIds", required=true) List<Long> productIds
In my opinion you should not use PathVariable but RequestParam (preferably RequestBody) in this case.
In case of using RequestParam it is should looks like:
#Path("/product/{customerId}")
List<ProductResponse> getProductData(
#ApiParam(value = "customerId", required = true) #PathParam("customerId") long customerId,
#ApiParam(value = "productIds", required = true) #RequestParam("productIds") List<Long> productIds
);
than your url will look like: http://localhost:50111/product-domain/api/product/7?productIds=2,3
In case of using RequestBody it is should looks like:
#Path("/product/{customerId}")
List<ProductResponse> getProductData(
#ApiParam(value = "customerId", required = true) #PathParam("customerId") long customerId,
#ApiParam(value = "productIds", required = true) #RequestBody("productIds") List<Long> productIds
);
than your url will look like: http://localhost:50111/product-domain/api/product/7
and your http request body should contains: [2, 3]
Why I advise against using #PathParam in this case?
Url length has length limit (around 2048 characters) - so if You try pass long list in future it is can be a problem
Url needs to "normalize"/"escape" special characters, what makes url less readable for human, which is the essence of using PathParam
BTW:
Consider using PathVariable instead of PathParam - because PathVariable is from Spring, but PathParam is from JAX-RS and I assume you want to use Spring Boot

Using Object class as wrapper for input in spring boot RestController

I am bit new to spring boot and I am trying to design a search on user history which will provide 3 attributes to search user history {userId, searchKey, SearchValue}.
The search value datatype may differ based on search.
E.g
Userid=100, SearchKey=userAddress, searchValue='10 Downing Street'
Userid=100, SearchKey=external, searchValue=true
Userid=100, SearchKey=companyId, searchValue=25
I am trying to design a rest endpoint as below. This endpoint will integrate with react front end.
#GetMapping(value = "/searchUserHistoryByKeyValue")
public ResponseEntity<Object> searchUserHistoryByKeyValue(
#RequestParam(value = "userId") int userId,
#RequestParam(value = "searchKey") String searchKey,
#RequestBody Object searchValue) {
List<org.json.simple.JSONObject> entities =
userHistoryService.searchUserHisotryByKeyValue(userId, searchKey, searchValue);
return new ResponseEntity<>(entities, HttpStatus.OK);
}
I have implemented a dynamodb search on userhistory object which takes input as generic searchValue object as search filter as below.
Dynamo DB Querying - https://www.tutorialspoint.com/dynamodb/dynamodb_querying.htm
public List<JSONObject> searchUserHistoryByKeyValue(
int userId, String searchKey, Object searchValue) throws DataAccessException {
Table table = dynamoDB.getTable(userHistoryTable.getName());
Map<String, String> expressionAttributeNames =
DEFAULT_USER_FILTERS.stream()
.collect(
Collectors.toMap(attrib -> attrib, attrib -> attrib.substring(1), (a, b) -> b));
Optional<String> projectionExpression =
createProjectionExpression(
Collections.singletonList(searchKey), expressionAttributeNames);
Optional<String> filterProjectionExpression =
buildCustomProjectionExpression(
Collections.singletonList(searchKey), expressionAttributeNames);
QuerySpec querySpec =
new QuerySpec()
.withProjectionExpression(projectionExpression.orElse(StringUtils.EMPTY))
.withKeyConditionExpression("#userId = :userId")
.withFilterExpression(
String.format(
"%s = :searchValue",
filterProjectionExpression.orElseThrow(
() -> new IllegalArgumentException("Invalid Search Attributes"))))
.withNameMap(expressionAttributeNames)
.withValueMap(Map.of(":userId", userId, ":searchValue", searchValue))
.withScanIndexForward(false);
When I am trying use swagger or postman to test this endpoint , I am not able to pass in
#RequestBody Object searchValue . it just shows as empty braces - {}
Also it shows below error as -
'TypeError: Failed to execute 'fetch' on 'Window': Request with
GET/HEAD method cannot have body. '
I am not able to make this work? Appreciate your insights on this.
It's HTTP protocol.
You cannot pass any body object with the Get method. You have to use Post or Put method for using a body in HTTP request.
#RequestBody not for single value it is intended for your custom object that is used with POST or PUT but in you case you can #RequestParam also if #RequestParam take attribute required with boolean vlue which tell your endpoint caller which params is optional if you set it False and which is required if you set it True

Pageable compenent is passed as null even we pass page,size,sort object

I have a rest controller that takes pageable as a parameter
#GetMapping(value = "/user", produces = APPLICATION_JSON_VALUE,
consumes = APPLICATION_JSON_VALUE)
public BaseResponse getUsers(
Pageable pageRequest) {
System.out.println(pageRequest);
);
}
now if i hit the url http://localhost:8080/user?page=1&size=20&sort=userId
i can see the syso getting printed as : Page request [number: 1, size 20, sort: userId: ASC]
but if i change the controller method and make pageable as required = false
#RequestParam(required= false)Pageable pageRequest
and if i hit the same url this time my syso will print null. I want to make pageable object as not required. How to achieve it
Basically my requirement is if the user triggers the url like the below
http://localhost:8080/user?page=1&size=20&sort=userId
and when i print my Pageable object it should print
Page request [number: 1, size 20, sort: userId: ASC]
but if i trigger my url like this http://localhost:8080/user
then my pageable object should be printed as null and not some default values

Spring Pageable object in get request from React using Axios

I have an endpoint looking like this
#GetMapping("/page") Page<Event> getEventPage( #PageableDefault(page = 0, size = 20) #SortDefault(sort = "createdDateTime", direction = Sort.Direction.DESC) Pageable pageable)
How am I supposed to pass the Pageable object from my React frontend using Axios, I got this so far:
fetchEvents(pageable) {
return axios.get("http://localhost:8080/api/events/page", pageable, this.setupAxiosInterceptors());
}
Where pageable is the last fetched page. Now it just resorts to the default values.
You simply do this by adding query parameters to the url. Like http://localhost:8080/api/events/page?page=1&size=20
The axios way to do this would be something like this:
const querystring = require('querystring');
axios.get('http://localhost:8080/api/events/page', querystring.stringify({ page: 1, size: 20 }));

Spring 4.1.5 MVC #RequestParam(required = false, value = "somevalue") fails if a parameter is absent

I have a spring mvc controller which is serving web service requests with multiple request parameters. All the parameters are marked required = false. Still if in the request a parameter is not available,
#RequestMapping(value = "/service/deployNew", method = RequestMethod.POST)
#ResponseBody public ResponseEntity<DeploymentId> deploy(HttpServletRequest request, HttpServletResponse response, #RequestParam(required = false, value = "abc") String abc, #RequestParam(required = false, value = "xyz") String xyz, #RequestParam(required = false, value = "uvw") String uvw,) throws Exception;
I see the error
required string parameter 'param' is not present
If I give a blank value to the param, everything works fine as below. Parameters abc and xyz has a blank value, but still I am passing it.
curl -i -X POST -H Accept:application/json "http://localhost:8080/Test/service/deploy.do?abc=&xyz=&uvw=somevalue"
If I remove any of the above param it will throw the error.
curl -i -X POST -H Accept:application/json "http://localhost:8080/Test/service/deploy.do?uvw=somevalue"
My service is being used by multiple clients with a single endpoint which caused some parameters to be present at times. I need to handle all the scenarios. Any idea?
Try to use defaultValue
#RequestParam(required = false, defaultValue = "somevalue")
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestParam.html#defaultValue--

Categories

Resources