Spring BootでRestTemplateの戻り値、ResponseEntityのステータスコードで分岐処理

`DefaultResponseErrorHandler` を設定するしないでステータスコードの取得方法が変わる
答えは[ここ](https://terasolunaorg.github.io/guideline/5.1.0.RELEASE/ja/ArchitectureInDetail/RestClient.html#restclienthowtouseerrorhandlingresponseentity)にあったけど、見逃していた

# 環境
Java : 11
JUnit : 4.12
Spring Boot : 2.1.6

# 設定するしないに関わらない共通のサンプルコード
```java:SandboxApplication.java
@SpringBootApplication
public class SandboxApplication {

    public static void main(String[] args) {
        SpringApplication.run(SandboxApplication.class, args);
    }

    // 雑にここでBean登録
    @Bean
    public RestTemplate setRestTemplate(){
        return new RestTemplate();
    }
}
```
```java:Hoge.java
class Hoge {
    String message;

    public Hoge(@JsonProperty("message") String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}
```
```java:SampleTest.java
@RunWith(SpringRunner.class)
@SpringBootTest
public class SampleTest {

    @Autowired
    RestTemplate restTemplate;
    @Autowired
    ObjectMapper objectMapper;
    @Autowired
    Sample sut;

    @Test
    public void テストだよ() throws Exception {
        // 2xx系 : ex) OK
        setUpMockRestServer(HttpStatus.OK);
        assertThat(sut.getHoge().getMessage(), is("200だよ"));

        // 4xx系エラー : ex) NOT_FOUND
        setUpMockRestServer(HttpStatus.NOT_FOUND);
        assertThat(sut.getHoge().getMessage(), is("404だよ"));

        // 5xx系エラー : ex) INTERNAL_SERVER_ERROR
        setUpMockRestServer(HttpStatus.INTERNAL_SERVER_ERROR);
        assertThat(sut.getHoge().getMessage(), is("500だよ"));
    }

    private void setUpMockRestServer(HttpStatus status) throws JsonProcessingException {
        MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build();
        String response = objectMapper.writeValueAsString(new Hoge(status.value() + "だよ"));
        mockServer.expect(requestTo("https://hoges/1"))
                .andRespond(withStatus(status).body(response).contentType(MediaType.APPLICATION_JSON_UTF8));
    }
}
```

# DefaultResponseErrorHandlerを設定しない

- クライアントエラー系(4xx)の場合、`HttpClientErrorException`
- サーバエラー系(5xx)の場合、`HttpServerErrorException`
- 自身で設定したコードの場合、`UnknownHttpStatusCodeException`  
上記をそれぞれ`try-catch`で扱う必要がある

```java:Sample.java
@Component
public class Sample {

    RestTemplate restTemplate;

    public Sample(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public Hoge getHoge() {
        ResponseEntity<Hoge> response;
        try {
            response = restTemplate.getForEntity("https://hoges/1", Hoge.class);
        } catch (HttpClientErrorException | HttpServerErrorException e) {
            // statusCodeによって分岐できる
            int statusCode = e.getStatusCode().value();
            return new Hoge(statusCode + "だよ");
        }

        return response.getBody();
    }
}
```


# DefaultResponseErrorHandlerを設定する
`DefaultResponseErrorHandler` を継承して、余計なことすんなという設定をすることで実現できる

```java:SampleResponseErrorHandler.java
@Component
public class SampleResponseErrorHandler extends DefaultResponseErrorHandler {
    @Override
    public void handleError(ClientHttpResponse response) throws IOException {
        // 何も書かないことで、サーバーエラーとクライアントエラーが起きても例外を発生させない
    }
}
```
```java:Sample.java
@Component
public class Sample {

    RestTemplate restTemplate;
    SampleResponseErrorHandler sampleResponseErrorHandler;

    public Sample(RestTemplate restTemplate, SampleResponseErrorHandler sampleResponseErrorHandler) {
        this.restTemplate = restTemplate;
        this.sampleResponseErrorHandler = sampleResponseErrorHandler;
    }

    public Hoge getHoge() {
        // 独自定義したErrorHandlerをRestTemplateに設定しておく
        restTemplate.setErrorHandler(sampleResponseErrorHandler);
        ResponseEntity<Hoge> response = restTemplate.getForEntity("https://hoges/1", Hoge.class);
        // サンプルではそのままreturnしているけど、ここでResponseEntityから取得できるステータスコードでいくらでも分岐できちゃう
        return response.getBody();
    }
}
```

# まとめ
ステータスコード取得して詳細に分岐したいのに、例外で拾えないよーってハマって辛かった。