I have a Java Spring Boot application with a couple of API REST endpoints.
In one of my endpoints I am using as a search endpoint.
My problem is calling this specific endpoint with a path variable containing a slash "/" in it will give me a HTTP 400 Bad Request. The program doesn't seen to find the current mapping at all.
ie if the search string is foo/bar then the following call gives me a HTTP status 400 - Bad Request:
curl -X PUT "http://127.0.0.1:8080/search/foo%2Fbar" \
-H "accept: application/json;charset=UTF-8" \
-H "Content-Type: application/json" \
-d "{ \"someSettings\": \"some value\", \"startNumber\": 0}"
This is how this part of the program looks like.
#PutMapping(value = "/search/{searchString}",
consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<SearchResultModel> search(#PathVariable("searchString") String searchString, #RequestBody SearchSettingsModel searchSettings) {
return handler.doSearch(searchString, searchSettings);
}
The search works fine when I have any other text string, and I prefer to use a PathVariable if possible. Is it possible to have the search in a PathVariable or do I have to put the string in the RequestBody instead?
I am using a Spring-Boot application with a Maven build with Java 11.
You can't have a %2F (= /) in your url.
Either add this to the body or as query parameter.
Related
I have a Java SpringBoot backend server and I wanted to test the controller classes with curl. However, whenever I send a request with the following format (in a powershell terminal):
curl --request POST --header "Content-Type: application/json" --data '{\"key\": 5}' http://localhost:8080/request
All the numerical values are changed to zeroes. And if in the DTO class I change them to Integer instead of int, then they are received as null. For strings, everything works perfectly.
This is what my controller methodlooks like:
#RestController
#RequestMapping("/request")
class MyController {
#PostMapping
public ResponseEntity<MuseumTO> createMuseum(#RequestBody RequestDTO request) {
System.out.println(request.key);
// ...
}
}
And the DTO class:
class RequestDTO {
public int key
}
GET requests work fine, and I've tried with two different backends, so I assume my problem is coming from the curl request's format. However, I've looked online and from what I've seen this is supposed to work.
There is a small issue in your CURL request. No need to use an escape character with "key". You are using a backslash with double quotes (\") that is not required.
Please try this CURL request.
curl --request POST --header "Content-Type: application/json" --data '{"key": 5}' http://localhost:8080/request
I have this API endpoint which expects one form-urlencoded array parameter. This is the relevant Java snippet:
#POST
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Produces(MediaType.APPLICATION_JSON)
public Response addItems(#Parameter(description = "Items to add") #FormParam("items") List<Long> items) {
return service.addItems(items);
}
I can't reach the endpoint from the generated Swagger UI because of the following error:
RESTEASY003870: Unable to extract parameter from http request: javax.ws.rs.FormParam("items") value is '1%2C2%2C3'
From what I read, Swagger is making this request:
curl -X 'POST' \
'http://localhost:8080/items' \
-H 'accept: */*' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'items=1,2,3'
It looks to me that the culprit is how Swagger serializes the array: Swagger sends this items=1,2,3 while RESTEasy expect this items=1&items=2&items=3.
I've already read the relevant Swagger documentation and tried every style/explode combination, including the ones that looks to have most sense for me (style = ParameterStyle.SIMPLE, explode = TRUE which by the way should be default behavior) with no luck.
So, how should I annotate this endpoint in order to Swagger to be able to invoke it?
I used https://github.com/quarkusio/quarkus-quickstarts/tree/main/openapi-swaggerui-quickstart and added your method to FruitResource
According to swagger documentation if you want to use form urlencoded
application/x-www-form-urlencoded is used to send simple ASCII text data as key=value pairs. The payload format is similar to query parameters.
at https://swagger.io/docs/specification/describing-request-body/, so it says use query params and I changed your function to
#POST
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
#Produces(MediaType.APPLICATION_JSON)
public Response addItems(
#Parameter(description = "Items to add") #QueryParam(
"items"
) List<Long> items
) {
return service.addItems(items);
}
and open the dev-ui
As you can see UI is preventing to add wrong parameters, correct ui below
and created curl command is working as expected.
curl -X 'POST' \
'http://localhost:8080/fruits?items=1&items=2' \
-H 'accept: */*' \
-d ''
in case you want to test the code it is here.
I'm using Spring boot 2.1.3-RELEASE. In my RestController I'm trying to set up a PUT method with one PathVariable and a RequestParam (application/x-www-form-urlencoded).
However when I call it the response is a bad request because the required RequestParam is not present.
I tried changing PutMapping to RequestMapping, swapping parameters position and using the syntax #RequestParam(value="param2", required=false) but nothing changes.
Curiously using PostMapping works. Also removing PathVariable works.
Here is the RestController code:
#PutMapping(value="/myurl/{param1}", consumes=MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String myMethod( #PathVariable("param1") Integer param1, #RequestParam("param2") String param2);
I call the method in this way:
curl -X PUT \
http://localhost:8080/myurl/42 \
-H 'Accept: application/json' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'param2=myparam2value'
The response is:
{
"timestamp": 1553613278534,
"status": 400,
"error": "Bad Request",
"message": "Required String parameter 'param2' is not present",
"path": "/myurl/42"
}
I expect that PUT works just like POST, but it seems not to.
Unfortunately I cannot send parameters as QueryParam, so I should maintain the same request call because I am refactoring an existing endpoint that works exactly this way.
Thanks
EDIT
I found this is caused by using an HandlerInterceptorAdapter (via WebMvcConfigurer).
For some reason, around
org.springframework.web.util.ContentCachingRequestWrapper.getParameterValues
org.apache.coyote.Request.parameters has no content and an exception is thrown, so it works only for POST and not for PUT (GET are handled differently).
I appreciate if someone can suggest if this can be reported as a bug considering that removing the interceptor made it work.
Regards
Use -G along with --data-urlencode:
curl -G -X PUT \
http://localhost:8080/myurl/42 \
-H 'Accept: application/json' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'param2=myparam2value'
From the documentation:
-G, --get
When used, this option will make all data specified with -d, --data, --data-binary or --data-urlencode to be used in an HTTP GET request instead of the POST request that otherwise would be used. The data will be appended to the URL with a ? separator. [...]
--data-urlencode <data>
(HTTP) This posts data, similar to the other -d, --data options with the exception that this performs URL-encoding. [...]
I defined a google cloud end point using java. the class method annotations looks like:
#Api(
name = "instaSmartApi",
version = "v1",
)
public class InstaSmartSvc {
#ApiMethod(name = "analyzeImage")
public Message analyzeImage(#Named("imgURL") String imgURL) {
...
}
I call it using curl which works is:
curl -H "Content-Type: application/json" -X POST -d '{"imgUrl" : "www.google.com"}' https://instasmarttagger.appspot.com/_ah/api/instaSmartApi/v1/analyzeImage/abc.jpg
this works fine except it ignores what i passed in request body.
The way I was expecting it to work:
curl -H "Content-Type: application/json" -X POST -d '{"imgUrl" : "www.google.com"}' https://instasmarttagger.appspot.com/_ah/api/instaSmartApi/v1/analyzeImage
But this returns not found. I am not sure why i have to append the method parameter in the end to make it work. Ideally i should pass that in the body. Please advise
I am making a curl post restful request to my jersey servlet in the form
curl -i -X POST -d "debit_user_id=/custome/mobile_number:917827448775"http://localhost:8080/switch/apikongcall.do/transactions
I need to fetch the debit_user_id in my servlet, code for my Post method is
#POST
//#Path("/transactions")
//#Consumes(MediaType.APPLICATION_JSON)
public Response createTrackInJSON(#QueryParam("debit_user_id") String debit_user_id) {
//Log logger = null;
this.logger = LogFactory.getLog(getClass());
this.logger.info("Inside post method"+debit_user_id);
String response = debit_user_id;
//String response = "testParam is: " + recipient_id + "\n";
//String result = "Track saved : " + track;
return Response.status(200).entity(response).build();
But my debit_user_id is coming as null. Is it the correct way to make the curl restful request or the way I am extracting it in my servlet is wrong.
I am new to jax-rs. Thanks in advance for the help.
The -d option to curl passes in a url encoded form parameter. You have to change #QueryParam to #FormParam to make the given Curl command work. Also, just specify the parameter name as mobile_number without the pathing that you used in you curl command, like so:
curl -i -X POST -d "debit_user_id=mobile_number:917827448775" http://localhost:8080/switch/apikongcall.do/transactions
maps to
#POST
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response createTrackInJSON(#FormParam("mobile_number") String debit_user_id) {
...
}
If you do in fact want a query parameter, your curl command would need to change:
curl -i -X POST http://localhost:8080/switch/apikongcall.do/transactions?mobile_number=917827448775
For security reasons, it's probably better to keep the mobile number in the message body, so I'd use the FormParam instead of the QueryParam.