Java/Spring

[Spring] RestTemplate

SeungbeomKim 2024. 11. 22. 18:27

 

카카오 OAuth 로그인을 구현해 보면서, RestTemplate을 사용하게 되었는데 RestTemplate이 무엇인지와 동작원리 등에 대해 정리해보려고 합니다.

 

RestTemplate

  • HTTP 통신을 위한 도구로 Rest API 웹 서비스와의 상호작용을 쉽게 할 수 있도록 도와주는 도구
  • HTTP 메서드를 제공하고 원격 서버와 동기적, 블로킹 방식으로 Json, xml 방식으로 다양한 데이터 형식으로 통신합니다.
  • Spring Framework의 핵심이 제공하는 동기식 RestClient

간단하게 외부 도메인과 Rest API을 제공하는 서비스와의 상호작용을 쉽게 해주는 도구로 해석하면 될 것 같은데요. 이제 동작 원리에 대해 설명드리도록 하겠습니다.

 

 

RestTemplate Flow

  1. Application이 RestTemplate을 생성하고, Uri, http method 등의 header를 담아 요청합니다.
  2. RestTemplate은 HttpMessageConverter를 사용하여 RequestEntity를 요청 메시지를 변환합니다.
  3. RestTemplate은 ClientHttpRequestFactory로부터 ClientHttpRequest를 가져와 요청을 보냅니다.
  4. ClientHttpRequest는 요청 메시지를 만들어 HTTP를 통해 서버와 통신합니다.
  5. RestTemplate은 ResponseErrorHandler로 오류를 확인하고 있다면 Error Handling 과정을 거칩니다.
  6. ClientHttpResponse에서 Error가 있다면, 이에 대해 처리하는 과정을 거칩니다.
  7. RestTemplate은 HttpMessageConverter를 이용하여 응답 메시지를 Java Object로 변환합니다.
  8. 애플리케이션에 반환합니다.

대략적으로 흐름이 이해되셨으면, Rest Resource와의 상호작용을 위한 메서드에 대해 알아보도록 하겠습니다.

 

https://www.geeksforgeeks.org/spring-resttemplate/

 

HTTP의 요청과 응답에 대한 메서드라고 생각하시면 될 것 같습니다. 그중에서도 exchange(), execute() 메서드는 ANY 옵션으로 어떤 HTTP 메서드가 들어와도 상관이 없습니다.

 

exchange() vs execute()

 

execute()

  1. RestTemplate 메서드 중 가장 범용적으로 사용되며, 아래와 같은 시나리오에 적합합니다.
  2. 모든 URL, HTTP 메서드 조합을 사용할 경우에 사용합니다.
  3. 요청을 보내기 전에, RequestCallback을 통해 요청을 다양하게 수정할 경우에 사용합니다.
  4. 응답 데이터를 ResponseExtractor를 통해 사용자 지정 방식으로 처리할 경우에 사용합니다.

 

exchange()

  1. execute에 비해 편리하게 사용할 수 있습니다.
  2. RequestCallback 대신, HttpEntity를 통해 body, header 등을 바로 전달할 수 있습니다.
  3. ResponseExtractor 없이, 내부적으로 응답 데이터를 처리합니다.

 

HTTP 요청, 응답의 자동 변환 및 역직렬화 (첨부한 다이어그램 참고)

  • 요청 및 응답을 자동으로 변환하고 역직렬화하는 기능을 제공합니다. 
  • 변환은 내부적으로 MessageConverter에 의해 자동으로 처리됩니다.
  • MessageConverter는 요청 및 응답 Body의 데이터 형식을 반환합니다. 

 

HTTP 요청, 응답을 다양한 형식으로 처리

  • Accept: 클라이언트가 서버에서 받기 원하는 미디어 타입을 지정합니다.
  • Content-Type: 서버에서 클라이언트로 보내는 미디어 타입을 지정합니다.
  • text/pain, application/json, application/xml 방식이 있습니다.

 

Header, Query Parameter 설정 지원

  • HttpHeaders 클래스의 add 메서드를 활용하여 Request Header를 설정합니다.
  • UriComponentsBuilder 클래스의 queryParam 메서드를 활용하여 Query Parameter를 설정합니다.

 

HTTP 요청/응답에 대한 로깅 지원

  • HTTP 요청과 응답을 가로채서 로그를 찍어볼 수 있습니다.
  • RestTemplate Bean 주입시, 구현한 Interceptor를 함께 주입시켜야 합니다.

 

사용 예시

RestTemplate restTemplate = new RestTemplateBuilder()
    .interceptors(new RestTemplateHeaderModifierInterceptor())
    .build();

public class RestTemplateHeaderModifierInterceptor
  implements ClientHttpRequestInterceptor {

    @Override
    public ClientHttpResponse intercept(
      HttpRequest request, 
      byte[] body, 
      ClientHttpRequestExecution execution) throws IOException {
 
        ClientHttpResponse response = execution.execute(request, body);
        response.getHeaders().add("Foo", "bar");
        return response;
    }
}

@Configuration
public class RestClientConfig {

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        List<ClientHttpRequestInterceptor> interceptors
          = restTemplate.getInterceptors();
        if (CollectionUtils.isEmpty(interceptors)) {
            interceptors = new ArrayList<>();
        }
        interceptors.add(new RestTemplateHeaderModifierInterceptor());
        restTemplate.setInterceptors(interceptors);
        return restTemplate;
    }
}

 

 

 

<참고 자료>

https://sjh836.tistory.com/141

 

RestTemplate (정의, 특징, URLConnection, HttpClient, 동작원리, 사용법, connection pool 적용)

참조문서 : https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html1. RestTemplate이란?spring 3.0 부터 지원한다. 스프링에서 제공하는 http 통신에 유용하게 쓸 수 있는

sjh836.tistory.com

https://stackoverflow.com/questions/52364187/resttemplate-exchange-vs-postforentity-vs-execute

 

RestTemplate: exchange() vs postForEntity() vs execute()

I am working on Rest API using Spring boot and I had to access an application's endpoint. I used RestTemplate for it. I was able to do it using 2 methods, postForEntity(): responseEntity =

stackoverflow.com