Central handling of Http Status error code with Spring Rest Template

In today’s post, we’ll cover how to implement a custom error handler for rest teamplate http status codes.

By Default, rest template throws Client type exception (400 series), Server type exception(500 series). In order to handle these kind of exceptions we simple put try/catch block wherever we required to make an api call.

However, when number of apis call incresed in a project then everywhere handling exceptions with try/catch blocks doesn’t sound good. It is good to have a reusable code which can be used from everywhere.

Spring rest template provides a better way to handle these kind of exceptions as below:

In order to make custom error handler, make a class which extends DefaultResponseErrorHandler class and override method of it as below:

package threadminions.resttemplateerror.errorhandler;

import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.DefaultResponseErrorHandler;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.stream.Collectors;

import static org.springframework.http.HttpStatus.NOT_FOUND;

public class RestErrorHandler extends DefaultResponseErrorHandler {

    @Override
    public void handleError(ClientHttpResponse clientHttpResponse) throws IOException {

        String body = new BufferedReader(new InputStreamReader(clientHttpResponse.getBody()))
                .lines().collect(Collectors.joining("\n"));

        String message;
        System.out.println("Status Code from Cloud Server:"+clientHttpResponse.getStatusCode().series());
        if(clientHttpResponse.getStatusCode().series() == HttpStatus.Series.CLIENT_ERROR)
        {
            message = "Some error occurred when making client request: " + body;
        }
        else if(clientHttpResponse.getStatusCode().series() == HttpStatus.Series.SERVER_ERROR)
        {
            message = "Error body receive from target server: " + body;
        }
        else if (clientHttpResponse.getStatusCode() == NOT_FOUND)
        {
            message = "Either URL is wrong and you are trying to hit wrong API: " + body;
        }
        else {
            message = "Some error occurred in making request to target server because of : " + body;
        }

        System.out.println(message);
        throw new CustomException(message);
    }
}

After making error handler, create a bean of rest template and set above error handler in it as below:

 package threadminions.resttemplateerror.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import threadminions.resttemplateerror.errorhandler.RestErrorHandler;

@Service
public class HttpServiceCall {

    @Autowired
    RestTemplate restTemplate;

    @Bean
    public RestTemplate restTemplate()
    {
        return new RestTemplateBuilder().errorHandler(new RestErrorHandler()).
                build();
    }
}

We are done with the required implementation. Let’s test the same.

In order to test the same write a test class as below:

package threadminions.resttemplateerror;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.client.ExpectedCount;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.web.client.RestTemplate;
import threadminions.resttemplateerror.errorhandler.CustomException;
import threadminions.resttemplateerror.errorhandler.RestErrorHandler;

import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;

@RunWith(SpringRunner.class)
@RestClientTest
public class RestTemplateErrorApplicationTests {


    @Autowired
    private MockRestServiceServer server;

    @Autowired
    private RestTemplateBuilder builder;

    @Test(expected = CustomException.class)
    public void contextLoads() {

        Assert.assertNotNull(this.builder);
        Assert.assertNotNull(this.server);

        RestTemplate restTemplate = this.builder
                .errorHandler(new RestErrorHandler())
                .build();

        this.server
                .expect(ExpectedCount.once(), requestTo("/abc/com"))
                .andExpect(method(HttpMethod.GET))
                .andRespond(withStatus(HttpStatus.NOT_FOUND));

        restTemplate.getForObject("abc/com",Object.class);
        this.server.verify();
    }

}

Let’s run your test cases and you will see following output on console:

Status Code from Cloud Server:CLIENT_ERROR
Some error occurred when making client request:

As you can see with above output, if something is wrong with rest template call then it goes into your custom error handler and handle exceptions accordingly.

Demo code can be found here.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s