Tratamento de erros RestTemplate de primavera

Tratamento de erros RestTemplate de primavera

1. Visão geral

Neste breve tutorial, discutiremos como implementar e injetar a interfaceResponseErrorHandler em uma instânciaRestTemplate - para lidar com erros de HTTP retornados por APIs remotas. 

2. Tratamento de erros padrão

Por padrão, oRestTemplate lançará uma dessas exceções no caso de um erro HTTP:

  1. HttpClientErrorException - em caso de status HTTP 4xx

  2. HttpServerErrorException – in caso de status HTTP 5xx

  3. UnknownHttpStatusCodeException – caso sin de um status HTTP desconhecido

Todas essas exceções são extensões deRestClientResponseException.

Obviously, the simplest strategy to add a custom error handling is to wrap the call in a try/catch block. Em seguida, processamos a exceção capturada como achamos adequado.

No entanto,this simple strategy doesn’t scale well conforme o número de APIs ou chamadas remotas aumenta. Seria mais eficiente se pudéssemos implementar um manipulador de erros reutilizável para todas as nossas chamadas remotas.

3. Implementando umResponseErrorHandler

E assim, uma classe que implementaResponseErrorHandler will lê o status HTTP da resposta e:

  1. Lance uma exceção significativa para nosso aplicativo

  2. Simplesmente ignore o status HTTP e deixe o fluxo de resposta continuar sem interrupção

Precisamos injetar a implementaçãoResponseErrorHandler na instânciaRestTemplate.

Portanto, usamosRestTemplateBuilder para construir o modelo e substituirDefaultResponseErrorHandler no fluxo de resposta.

Então, vamos primeiro implementar nossoRestTemplateResponseErrorHandler:

@Component
public class RestTemplateResponseErrorHandler
  implements ResponseErrorHandler {

    @Override
    public boolean hasError(ClientHttpResponse httpResponse)
      throws IOException {

        return (
          httpResponse.getStatusCode().series() == CLIENT_ERROR
          || httpResponse.getStatusCode().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();
            }
        }
    }
}

Em seguida, construímos a instânciaRestTemplate usando o sintroduceRestTemplateBuilder to nossoRestTemplateResponseErrorHandler:

@Service
public class BarConsumerService {

    private RestTemplate restTemplate;

    @Autowired
    public BarConsumerService(RestTemplateBuilder restTemplateBuilder) {
        RestTemplate restTemplate = restTemplateBuilder
          .errorHandler(new RestTemplateResponseErrorHandler())
          .build();
    }

    public Bar fetchBarById(String barId) {
        return restTemplate.getForObject("/bars/4242", Bar.class);
    }

}

4. Testando nossa implementação

Finalmente, vamos testar este manipulador simulando um servidor e retornando um statusNOT_FOUND:

@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() {
        Assert.assertNotNull(this.builder);
        Assert.assertNotNull(this.server);

        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();
    }
}

5. Conclusão

Este artigo apresentou uma solução para implementar e testar um manipulador de erros personalizado para umRestTemplate que converte erros HTTP em exceções significativas.

Como sempre, o código apresentado neste artigo está disponívelover on Github.