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.

Programmer DD
Programmer DD
Programmer DD
How to Create a Custom RestTemplate ResponseErrorHandler in Spring

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendJavaError Handlingresttemplate
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.