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
Related
I have an api that consumes multipart/form-data and produces application/json. The form-data contains a UUID string. When I make a request to that api, it gives an 400 BAD_REQUEST status, stating that some mostSigBits and leastSigBits of the UUID instance is missing. I figured that the UUID instance might have been instantiated with some missing requirements.
How can I resolve this?
Here's my api.
#PatchMapping(value = "/{username}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_PROBLEM_JSON_VALUE)
#Transactional
public ResponseEntity<?> takeThisGiveThat(UUID uuid, String somestring, String someMoreString) {
return ResponseEntity.ok(Map.of("uuid", uuid, "somestring", somestring, "someMoreString", someMoreString));
}
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
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?
In Spring Boot 1.5.4 I have a request mapping like this:
#RequestMapping(value = "/graph/{graphId}/details/{iri:.+}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public JSONObject getGraph(#PathVariable Long graphId,
#PathVariable String iri) {
log.debug("Details called for graph ID {} for IRI {}", graphId, iri);
return detailsService.getDetails(graphId, iri);
}
Accessing
http://localhost:9000/api/v1/graph/2/details/http%3Anthnth33
works fine and the server maps the request correctly and the code returns the expected result
But accessing
http://localhost:9000/api/v1/graph/2/details/http%3A%2F%2Fserverurl.net%2Fv1%2Fus%2Fh.schumacher%408tsch.net%2Fn%2FLouSchumacher
gives a bad server request (Failed to load resource: the server responded with a status of 400 (Bad Request)). The request mapping to the end point isn't even done in that case.
Obviously the slash '/' encoded as %2F (using encodeURIComponent()) causes trouble. Why? What am I missing? How should uri parameter then be encoded?
The question is not only about how to extract PathVariables but more on how to force String to recognize the correct mapping.
The issue with your example is how Spring is doing path matching. The URL you have provided as example
http://localhost:9000/api/v1/graph/2/details/http%3A%2F%2Fserverurl.net%2Fv1%2Fus%2Fh.schumacher%408tsch.net%2Fn%2FLouSchumacher
will be decoded into by container
http://localhost:9000/api/v1/graph/2/details/http://serverurl.net/v1/us/h.schumacher#8tsch.net/n/LouSchumacher
before processing by Spring matcher. This makes matche think that this only http: corresponds {iri:.+} and as later goes / so it is some longer path you don't have a mapping for.
The approach described here should work for you: Spring 3 RequestMapping: Get path value
#RequestMapping(value = "/graph/{graphId}/details/**",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public JSONObject getGraph(#PathVariable Long graphId,
HttpServletRequest request) {
String iri = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
log.debug("Details called for graph ID {} for IRI {}", graphId, iri);
return detailsService.getDetails(graphId, iri);
}
I have the following API endpoint:
#ApiResponses(
value = {
#ApiResponse(code = 200, message = "OK",
responseHeaders = {
#ResponseHeader(name = "X-RateLimit-Limit", description = "The defined maximum number of requests available to the consumer for this API.", response = Integer.class),
#ResponseHeader(name = "X-RateLimit-Remaining", description = "The number of calls remaining before the limit is enforced and requests are bounced.", response = Integer.class),
#ResponseHeader(name = "X-RateLimit-Reset", description = "The time, in seconds, until the limit expires and another request will be allowed in. This header will only be present if the limit is being enforced.", response = Integer.class)
}
)
}
)
#ApiOperation(httpMethod = "GET", hidden = false, nickname = "Get Network Availability in JSON", value = "Get network availability for a product", response = AvailableToPromise.class, position = 1)
#RequestMapping(value = "/{product_id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> networkAvailabilityJsonResponse(
#RequestHeader HttpHeaders headers,
#PathVariable("product_id") String productId,
#Valid NetworkAvailabilityCmd cmd, //query params
BindingResult result)
throws Exception {}
}
Certain parameters, such as key are taken from the query and mapped into this object through Spring MVC.
However, in the parameters section of my endpoint in the swagger-ui, it's showing me a few odd things:
None of the variables that are in NetworkAvailabilityCmd show in this parameters list, and cmd itself shows as being located in the request body (it's actually located in the query). Is there a way to hide cmd and extract the params inside this object to show on the params list? I'd like the params list to look like this (with more params):
I'm able to do this if I use #ApiImplicitParams on the method endpoint, and write out each of the params. However, this NetworkAvailabilityCmd is used for many endpoints, and having the list of params on each endpoint is very messy. Being able to extract the variables from in the object would be far cleaner, and would prevent people from forgetting to add the entire list to new endpoints.
I imagine that it requires an annotation on NetworkAvailabilityCmd cmd, and potentially something on the variables in that class, but I can't seem to find what I'm looking for in the docs.
Thanks!
I found out that adding #ModelAttribute worked magically. This annotation is from Spring.