Spring RestTemplateのエラー処理

Spring RestTemplateエラー処理

1. 概要

この短いチュートリアルでは、RestTemplateインスタンスにResponseErrorHandlerインターフェースを実装して挿入する方法について説明します。これにより、リモートAPIから返されるHTTPエラーを適切に処理できます。 

2. デフォルトのエラー処理

デフォルトでは、HTTPエラーの場合、RestTemplateは次のいずれかの例外をスローします。

  1. HttpClientErrorException –HTTPステータス4xxの場合

  2. HttpServerErrorException – HTTPステータス5xxの場合

  3. 不明なHTTPステータスの場合のUnknownHttpStatusCodeException – in

これらの例外はすべて、RestClientResponseExceptionの拡張です。

Obviously, the simplest strategy to add a custom error handling is to wrap the call in a try/catch block.次に、キャッチされた例外を適切と思われる方法で処理します。

ただし、リモートAPIまたは呼び出しの数が増えるとthis simple strategy doesn’t scale wellになります。 すべてのリモート呼び出しに再利用可能なエラーハンドラーを実装できれば、より効率的です。

3. ResponseErrorHandlerの実装

したがって、ResponseErrorHandler を実装するクラスは、応答からHTTPステータスを読み取ります。

  1. アプリケーションにとって意味のある例外をスローします

  2. HTTPステータスを無視し、応答フローを中断せずに続行します

ResponseErrorHandler実装をRestTemplateインスタンスに挿入する必要があります。

したがって、RestTemplateBuilderを使用してテンプレートを作成し、応答フローのDefaultResponseErrorHandlerを置き換えます。

それでは、最初にRestTemplateResponseErrorHandler:を実装しましょう

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

次に、RestTemplateBuilder to を使用してRestTemplateインスタンスを構築し、RestTemplateResponseErrorHandler:を紹介します。

@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. 実装のテスト

最後に、サーバーをモックしてNOT_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. 結論

この記事では、HTTPエラーを意味のある例外に変換するRestTemplateのカスタムエラーハンドラーを実装してテストするためのソリューションを紹介しました。

いつものように、この記事で紹介されているコードはover on Githubで利用できます。