Search code examples
springexceptionresttemplate

How to pass and handle Exceptions through HTTP responses in Spring?


I have a Client and Server module in my Spring project running on separate ports. The Client module makes a POST request to the Server via a RestTemplate. The Server-Module throws a custom Exception with a custom error-message. Currently, in my Project, the Server has a RestControllerAdvice Class that handles such exceptions as follows:

@RestControllerAdvice
public class AppRestControllerAdvice {
    @ExceptionHandler(ApiException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public MessageData handle(ApiException e) {
        MessageData data = new MessageData();
        data.setMessage(e.getMessage());
        return data;
    }
}

On the Client side, the following method catches the Response from the Server.

@RestControllerAdvice
public class AppRestControllerAdvice {
    @ExceptionHandler(ApiException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public MessageData handle(ApiException e) {
        MessageData data = new MessageData();
        data.setMessage(e.getMessage());
        return data;
    }

    @ExceptionHandler(Throwable.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public MessageData handle(Throwable e) {
        MessageData data = new MessageData();
        data.setMessage("UNKNOWN ERROR- " + e.getMessage());
        e.printStackTrace();
        return data;
    }
}

Whenever the Exception is thrown on the server, here is what I receive on the Client

{
  "message": "UNKNOWN ERROR- org.springframework.web.client.HttpClientErrorException: 400 Bad Request"
}

My question is, how do I retrieve the Custom Exception message that originated on the Server?

Also, why isn't the correct RestControllerAdvice module on the Client side picking up the error? (The INTERNAL_SERVER_ERROR method catches the error instead of the BAD_REQUEST method.)


Solution

  • My question is, how do I retrieve the Custom Exception message that originated on the Server?

    To retrieve the orignal exception message you have to use dedicated ResponseErrorHandler that is capable of extracting that information, rather than using the default one (DefaultResponseErrorHandler - which I assume you use because of the message you got - org.springframework.web.client.HttpClientErrorException: 400 Bad Request).

    Create:

    public class CustomerResponseErrorHandler extends DefaultResponseErrorHandler {
    
        @Override
        public void handleError(ClientHttpResponse httpResponse) throws IOException {
    
            // here you have access to the response's body which potentially contains the exception message you are interested in  
            // simply extract it if possible and throw an exception with that message
            // in other case you can simply call `super.handlerError()` - do whatever suits you
    
        }
    }
    

    Then use it with your RestTemplate:

    @Configuration
    public class RestTemplateConfig {
    
        @Bean
        public RestTemplate restTemplate(RestTemplateBuilder builder) {
            return builder
              .errorHandler(new CustomerResponseErrorHandler())
              .build();
        }
    
    }
    

    Also, why isn't the correct RestControllerAdvice module on the Client side picking up the error? (The INTERNAL_SERVER_ERROR method catches the error instead of the BAD_REQUEST method.)

    The correct method is executed - your RestTemplate at the moment is throwing HttpClientErrorException which is not an ApiException. It is a Throwable though.