LoginSignup
8

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-06-24

DefaultResponseErrorHandler を設定するしないでステータスコードの取得方法が変わる
答えはここにあったけど、見逃していた

環境

Java : 11
JUnit : 4.12
Spring Boot : 2.1.6

設定するしないに関わらない共通のサンプルコード

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();
    }
}
Hoge.java
class Hoge {
    String message;

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

    public String getMessage() {
        return message;
    }
}
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で扱う必要がある
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 を継承して、余計なことすんなという設定をすることで実現できる

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

まとめ

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8