1.概要

この短いチュートリアルでは、

RestTemplate

インスタンスに

ResponseErrorHandler

インターフェースを実装して注入し、リモートAPIから返されたHTTPエラーを適切に処理する方法について説明します。

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

デフォルトでは、HTTPエラーが発生した場合、

RestTemplate

は次のいずれかの例外をスローします。


  1. HttpClientErrorException

    – HTTPステータス4xxの場合



  2. _HttpServerErrorException – HTTPステータスが5xxの場合は

    _



  3. _UnknownHttpStatusCodeException – 不明なHTTPステータスの場合は

    _

これらの例外はすべて

RestClientResponseException

の拡張です。

  • 明らかに、カスタムエラー処理を追加するための最も簡単な戦略は、呼び出しを

    try/catch

    ブロックでラップすることです。

ただし、リモートAPIまたはリモート呼び出しの数が増えると、

この単純な方法ではうまく拡張できません

。すべてのリモート呼び出しに対して再利用可能なエラーハンドラを実装できれば、さらに効率的になります。

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

次に、

RestTemplateResponseErrorHandlerを導入するために


RestTemplateBuilderを使用して

RestTemplate__インスタンスを構築します。

@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

のカスタムエラーハンドラを実装してテストするための解決策を紹介しました。

いつものように、この記事で紹介したコードはhttps://github.com/eugenp/tutorials/tree/master/spring-resttemplate[over on Github]から入手できます。