masato-ka's diary

日々思ったこととか、やったことの備忘録。

RestTemplateでレスポンスヘッダ内のContent-Typeを変更する。

この記事で紹介すること

この記事ではSpringのRestTemplateで受け取ったレスポンスのContent-Typeを変更し、任意のHttpMessageConverterを実行させる方法を考えたのでメモとして記載します。この記事はQiitaに投稿した記事をサンプルとして転載しています。

外部のAPIサーバを利用した際に、JSONフォーマットのbodyにContent-Type: text/plainで帰ってくることがありました。レスポンスのJSONに対応したBeanに値をバインドさせようとしてもContent-Typeがtext/plainのため、期待したHttpMessageConverterにマッピングされません。 そこで、RestTemplateにレスポンスのヘッダを変更するClientHttpRequestInterceptorを登録し解決しました。

ClientHttpRequestInterceptorの実装とRestTemplateBuilderの利用方法は以下のサイトを参考にしました。

またBing Speech API を対象に今回の内容を実装したものを以下のリポジトリに置いています。認証などの要素も入っているため、今回の説明とは多少異なります。 https://github.com/masato-ka/speech-api-proxy-service

ClientHttpRequestInterceptorの実装

  • ResponseHeaderInterceptor.java
@Component
public class ResponseHeaderInterceptor implements ClientHttpRequestInterceptor {
    
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
            throws IOException {       
        ClientHttpResponse response = execution.execute(request, body);//(1)
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);//(2)
        return response;
    }

}

(1)実際のリクエスト実行処理

(2)リクエスト実行後、レスポンスオブジェクトのContentTypeをapplication/jsonで上書きします。

RestTemaplateの設定と実行

@Component
public class RestClient {
        
        private final String apiUri = "https://hoge.com/api/v1/foo"
        private final RestTemplate restTemplate;
    
    public RestClient(RestTemplateBuilder restTemplateBuilder,
              ResponseHeaderInterceptor interceptor){//(1)
        restTemplate = restTemplateBuilder.additionalInterceptors(interceptor).build();//(2)
    }
    
    public Result request(){

        URI targetUri = UriComponentsBuilder
                                      .fromUriString(apiUri)
                                      .build()
                                      .toUri();
        
        Result result = restTemplate.getForObject(targetUri, Result.class);//(3)
        return result;
    }
    
}

(1) ResponseHeaderInterceptorをInjection

(2) RestTemplateBuilderを通してResponseHeaderInterceptorをRestTemaplateに設定

(3) リクエストを実行、この際にResponseHeaderInterceptorの処理がフックされる

まとめ

そもそもサービス側がContent-Typeを正しく返してくれればいいのですが、コントロールできない他者のサービスだったため、このような方法をとりました。  そもそもInterceptorを実装しない簡単な方法があるかもしれません。