4
votes

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

1
some.endpoint/api/v1/users{id}?selector={foo} -- id -> PathParam and foo -> RequestParam. My guess is you're conflating "RequestParam" with "body of HTTP request". If your 'param2' is the body of the request, remove the @RequestParam annotation.Not a JD
Can you try this : curl -X PUT \ localhost:8080/myurl/42?param2=myparam2value \ -H 'Accept: application/json' \ -H 'Content-Type: application/x-www-form-urlencoded' \Logan Wlv
The params come into the request body, not in the param.Roman C
Thank you @Logan Wlv. Unfortunately I need to maintain the same call convention because I am refactoring an existing endpoint.Dave

1 Answers

1
votes

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. [...]