Reputation: 2775
I have an endpoint in my controller configured as such:
@RequestMapping(value = "/users/{userId}/data", method = RequestMethod.GET)
public void getUserData(@PathVariable("userId") @Valid @NotNull Integer userId, HttpServletRequest request) {
}
If the client sends request to this endpoint with blank userId
, I'm assuming Spring is interpreting the URL as /users//data
because this exception is thrown:
2017-03-03 11:13:41,259 [[ACTIVE] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'] ERROR class com.xxxx.web.controller.custom.ExceptionHandlingController: RuntimeException thrown: org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: "data"
What is the best way to handle this use case? I'm wary about casting userId
as a String and catching the exception, that seems like a hack. I do not want to rely on the client always sending a proper request either. I am currently using Spring-Boot v1.2.6.RELEASE and am willing to upgrade versions if I know that will fix it.
Upvotes: 0
Views: 2316
Reputation: 10300
You have a conflict in your request mapping.
Most likely you also have GET mapping for /users/{userId}
. This is the mapping which was applied instead of the one from your question.
The issue is that you request for /users//data
, web server automatically replaces double slash by single slash. The result request exactly matches to this pattern /users/{userId}
but not to the one you posted. Finally spring can't cast data
as an integer.
If you remove /users/{userId}
(just for test reasons) you'll probably get 404 error code requesting the same url.
EDIT:
In fact you should not care that someone sends wrong requests to your REST API. REST API is a contract and both sides should follow this contract. You as a backend point should only handle a request and provide appropriate error code and good description in case if the request is wrong. data
was never a correct user-id make sure this information is included into the response instead of that technical stuff.
One of the possible solutions is to validate ids using pattern. In your case it will look like this:
@RequestMapping(value = "/users/{userId:\\d+}/data", method = GET)
@RequestMapping(value = "/users/{userId:\\d+}", method = GET)
In this case spring will automatically filter non-number ids and provide HTTP 404 for them.
Upvotes: 0
Reputation: 5813
You can create a class to handle global exceptions and annotate it with @ControllerAdvice.
@ControllerAdvice
public class CustomRestExceptionHandler extends ResponseEntityExceptionHandle {
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<Object> handleMethodArgumentTypeMismatch(
MethodArgumentTypeMismatchException ex, WebRequest request) {
//Handle your exception here...
}
}
Here is a good write up on how to a lot of things you can do with @ControllerAdivce
http://www.baeldung.com/global-error-handler-in-a-spring-rest-api
Upvotes: 1