How to Create a Custom RestTemplate ResponseErrorHandler in Spring
This tutorial explains how to implement a custom ResponseErrorHandler for Spring's RestTemplate, inject it via RestTemplateBuilder, and test it with a mock server to gracefully convert HTTP errors into meaningful application exceptions.
Overview
In this short tutorial we discuss how to implement a custom ResponseErrorHandler class and inject it into a RestTemplate instance, allowing graceful handling of HTTP errors when calling remote APIs.
Default Error Handler
By default, RestTemplate throws one of the following exceptions for HTTP errors: HttpClientErrorException – for 4xx status codes HttpServerErrorException – for 5xx status codes UnknownHttpStatusCodeException – for unknown status codes
All these exceptions inherit from RestClientResponseException. The simplest way to add custom error handling is to wrap calls in try/catch blocks, but this approach does not scale well when many remote APIs are involved.
Implement a Custom ResponseErrorHandler
The custom handler should read the HTTP status from the response and:
Throw an exception meaningful to the application.
Optionally ignore the status code and let the response stream continue.
We also need to inject the custom handler into the RestTemplate using RestTemplateBuilder to replace the default handler.
@Component
public class RestTemplateResponseErrorHandler implements ResponseErrorHandler {
@Override
public boolean hasError(ClientHttpResponse httpResponse) throws IOException {
return (httpResponse.getStatusCode().series() == HttpStatus.Series.CLIENT_ERROR
|| httpResponse.getStatusCode().series() == HttpStatus.Series.SERVER_ERROR);
}
@Override
public void handleError(ClientHttpResponse httpResponse) throws IOException {
if (httpResponse.getStatusCode().series() == HttpStatus.Series.SERVER_ERROR) {
// handle SERVER_ERROR
} else if (httpResponse.getStatusCode().series() == HttpStatus.Series.CLIENT_ERROR) {
// handle CLIENT_ERROR
if (httpResponse.getStatusCode() == HttpStatus.NOT_FOUND) {
throw new NotFoundException();
}
}
}
}Injecting the Handler
@Service
public class BarConsumerService {
private RestTemplate restTemplate;
@Autowired
public BarConsumerService(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder
.errorHandler(new RestTemplateResponseErrorHandler())
.build();
}
public Bar fetchBarById(String barId) {
return restTemplate.getForObject("/bars/4242", Bar.class);
}
}Testing the Handler
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {NotFoundException.class, Bar.class})
@RestClientTest
public class RestTemplateResponseErrorHandlerIntegrationTest {
@Autowired
private MockRestServiceServer server;
@Autowired
private RestTemplateBuilder builder;
@Test(expected = NotFoundException.class)
public void givenRemoteApiCall_when404Error_thenThrowNotFound() {
RestTemplate restTemplate = this.builder
.errorHandler(new RestTemplateResponseErrorHandler())
.build();
this.server.expect(ExpectedCount.once(), requestTo("/bars/4242"))
.andExpect(method(HttpMethod.GET))
.andRespond(withStatus(HttpStatus.NOT_FOUND));
Bar response = restTemplate.getForObject("/bars/4242", Bar.class);
this.server.verify();
}
}Summary
The article provides a solution for creating and testing a custom error handler for RestTemplate, enabling conversion of HTTP errors into meaningful exceptions. The complete source code is available on GitHub.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
