Spring Resttemplate exception handling

267,139

Solution 1

You want to create a class that implements ResponseErrorHandler and then use an instance of it to set the error handling of your rest template:

public class MyErrorHandler implements ResponseErrorHandler {
  @Override
  public void handleError(ClientHttpResponse response) throws IOException {
    // your error handling here
  }

  @Override
  public boolean hasError(ClientHttpResponse response) throws IOException {
     ...
  }
}

[...]

public static void main(String args[]) {
  RestTemplate restTemplate = new RestTemplate();
  restTemplate.setErrorHandler(new MyErrorHandler());
}

Also, Spring has the class DefaultResponseErrorHandler, which you can extend instead of implementing the interface, in case you only want to override the handleError method.

public class MyErrorHandler extends DefaultResponseErrorHandler {
  @Override
  public void handleError(ClientHttpResponse response) throws IOException {
    // your error handling here
  }
}

Take a look at its source code to have an idea of how Spring handles HTTP errors.

Solution 2

Spring cleverly treats http error codes as exceptions, and assumes that your exception handling code has the context to handle the error. To get exchange to function as you would expect it, do this:

    try {
        return restTemplate.exchange(url, httpMethod, httpEntity, String.class);
    } catch(HttpStatusCodeException e) {
        return ResponseEntity.status(e.getRawStatusCode()).headers(e.getResponseHeaders())
                .body(e.getResponseBodyAsString());
    }

This will return all the expected results from the response.

Solution 3

You should catch a HttpStatusCodeException exception:

try {
    restTemplate.exchange(...);
} catch (HttpStatusCodeException exception) {
    int statusCode = exception.getStatusCode().value();
    ...
}

Solution 4

Another solution is the one described here at the end of this post by "enlian": http://springinpractice.com/2013/10/07/handling-json-error-object-responses-with-springs-resttemplate

try{
     restTemplate.exchange(...)
} catch(HttpStatusCodeException e){
     String errorpayload = e.getResponseBodyAsString();
     //do whatever you want
} catch(RestClientException e){
     //no response payload, tell the user sth else 
}

Solution 5

Spring abstracts you from the very very very large list of http status code. That is the idea of the exceptions. Take a look into org.springframework.web.client.RestClientException hierarchy:

You have a bunch of classes to map the most common situations when dealing with http responses. The http codes list is really large, you won't want write code to handle each situation. But for example, take a look into the HttpClientErrorException sub-hierarchy. You have a single exception to map any 4xx kind of error. If you need to go deep, then you can. But with just catching HttpClientErrorException, you can handle any situation where bad data was provided to the service.

The DefaultResponseErrorHandler is really simple and solid. If the response status code is not from the family of 2xx, it just returns true for the hasError method.

Share:
267,139

Related videos on Youtube

vaibhav
Author by

vaibhav

Updated on April 12, 2022

Comments

  • vaibhav
    vaibhav about 2 years

    Below is the code snippet; basically, I am trying to propagate the exception when the error code is anything other than 200.

    ResponseEntity<Object> response = restTemplate.exchange(url.toString().replace("{version}", version),
                        HttpMethod.POST, entity, Object.class);
                if(response.getStatusCode().value()!= 200){
                    logger.debug("Encountered Error while Calling API");
                    throw new ApplicationException();
                }
    

    However in the case of a 500 response from the server I am getting the exception

    org.springframework.web.client.HttpServerErrorException: 500 Internal Server Error
        at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:94) ~[spring-web-4.2.3.RELEASE.jar:4.2.3.RELEASE]
    

    Do I really need to wrap the rest template exchange method in try? What would then be the purpose of codes?

    • Mudassar
      Mudassar almost 8 years
      Kindly share the code of ApplicationException()
  • vaibhav
    vaibhav almost 8 years
    IMO the response should always come with an appropriate status code, otherwise whats the purpose of codes.
  • Stefano Scarpanti
    Stefano Scarpanti over 6 years
    I am not sure to understand @vaibhav objection: catching HttpStatusCodeException is not for a wrong code, but because in many cases an exception is always thrown and so your if(code==value) can never be executed.
  • Agoston Horvath
    Agoston Horvath over 6 years
    Exceptions are very costly in Java. It's OK for the occasional, unexpected causes (hence the name), but over that, you should look for other solutions instead.
  • IcedDante
    IcedDante about 6 years
    "Very costly"? More costly than, say, making an HTTP call?
  • Raffael Bechara Rameh
    Raffael Bechara Rameh about 6 years
    How can we get response body from the exception? Is it possible?
  • Dave
    Dave about 6 years
    @AgostonHorvath - rubbish. In this case you've paid the price of the exception already anyway. The point here is to transform it from an otherwise useless HttpClientException into a more meaningful application specific exception using the returned JSON error object.
  • Dave
    Dave about 6 years
    @RaffaelBecharaRameh - HttpStatusCodeException .getResponseBodyAsString() or HttpStatusCodeException.getResponseBodyAsByteArray().
  • Agoston Horvath
    Agoston Horvath about 6 years
    @Dave there is no exception created if you process the error via a handler, like the answer above.
  • Dave
    Dave almost 6 years
    @AgostonHorvath - the cost of the exception includes the context setup for exception handling that the JVM does whenever it encounters a try block - this is the cost already paid to which I referred. The cost of generating the stack trace is relatively minor although not completely insignificant. Your assertion that "Exceptions are very costly in Java" within a context where some form of error handling must happen, is false.
  • Dave
    Dave almost 6 years
    FWIW I personally use the custom ResponseErrorHandler approach, but not because I am trying to avoid using Java exception handling. My reason is because the response body in such cases is the serialized exception.
  • Agoston Horvath
    Agoston Horvath almost 6 years
    @Dave The try-catch block is practically free. It's new()'ing and throw'ing the exception that is expensive. See stackoverflow.com/questions/17966265/…
  • mvmn
    mvmn almost 6 years
    I have 1 instance of RestTemplate that I reuse for different calls. I need to handle errors from different calls differently - apparently there is no way to do that with global handler - I need to provide a handler per request.
  • Federico Bellucci
    Federico Bellucci almost 6 years
    With this error handler I always get a ResourceAccessException because RestTemplate.doExecute catches IOExceptions and throws a ResourceAccessException. What am I doing wrong?
  • Agoston Horvath
    Agoston Horvath over 5 years
    Like I said like 6 comments earlier, "@Dave there is no exception created if you process the error via a handler, like the answer above. "
  • Crenguta S
    Crenguta S over 5 years
    I was able to solve this by extending DefaultResponseErrorHandler.
  • razor
    razor over 5 years
    you need to use different HttpClient than default SDK, to get response body for errors
  • razor
    razor over 5 years
    you need to use different HttpClient than default SDK, to get response body for errors (for example apache commons HttpClient)
  • razor
    razor over 5 years
    you need to use different HttpClient than default SDK, to get response body for errors (for example apache commons HttpClient)
  • razor
    razor over 5 years
    you need to use different HttpClient than default SDK, to get response body for errors (for example apache commons HttpClient)
  • The-Proton-Resurgence
    The-Proton-Resurgence about 5 years
    'org.springframework.web.client.HttpClientErrorException' is a subclass of 'org.springframework.web.client.HttpStatusCodeException'. You don't need to catch HttpClientErrorException if you are already catching HttpStatusCodeException and doing nothing different in handling the above two exceptions.
  • chill appreciator
    chill appreciator about 4 years
    Dude, thanks for the explanation. How did you build this tree with exception hierarchy?
  • Perimosh
    Perimosh about 4 years
    Hey man, I used Eclipse. Just press control+shift+T to open the type searcher, and type RestClientException. Double click on RestClientException from the results, Eclipse will open that class for you. Then, put the mouse cursor over the class name (where it says "public class RestClientException...", and press control+T. You will see that hierarchy.
  • Perimosh
    Perimosh almost 4 years
    did you try it?
  • chill appreciator
    chill appreciator almost 4 years
    Btw in Intellij it is: click on the class in project tree and Ctrl + Alt + U, or right mouse click -> Build diagram
  • lorrainebatol
    lorrainebatol over 3 years
    this is helpful, thanks, though I would disagree that assuming things is a clever thing to do
  • Raphael
    Raphael over 3 years
    "cleverly" -- citation needed
  • austin cherlo
    austin cherlo over 3 years
    Clever aka en.wikipedia.org/wiki/Kludge as opposed to KISS principles-wiki.net/principles:keep_it_simple_stupid. Some developers do not like to use exception handling as a method of process control.
  • Manoj Majumdar
    Manoj Majumdar almost 3 years
    @CrengutaS the DefaultResponseErrorHandler's handleError method is called, but ultimately the HttpClientErrorException gets propagated to the client. How have you handled that in your handler?