RestTemplate 정리 - Kim-Taesu/study GitHub Wiki

바쁘신 분들을 위해 내가 개발하면서 애매했던 부분을 먼저 정리하겠다.

  • 좀 더 아래 글에 상세 내용이 정리 되어 있다.

execute vs exchange vs XXXForEntity vs XXXForObject

  • 결론적으로는 모두 메서드 내부에서 execute를 호출하기 때문에 성능적으로 큰 차이가 없다.
  • 사용 방법에 따라 갈린다.
  • https://stackoverflow.com/a/52364898

나는 HTTP method에서 사용되는 request를 커스텀하게 설정하고, 요청 결과인 response도 커스텀하게 설정하고 싶다!

  • execute를 사용하면 된다.
  • RequestCallback 인터페이스의 doWithRequest 메서드를 구현하여 원하는 방식으로 request를 설정하면 된다.
  • ResponseExtractor 인터페이스의 extractData 메서드를 구현하여 원하는 방식으로 response의 데이터를 추출하면 된다.

나는 request 응답을 ResponseEntity 형태로 받고 싶다!

  • exchange, XXXForEntity를 사용하면 된다.
  • XXXForEntity는 메소드 명에 따라 HTTP method가 정해져있다.
  • header, body는 Object request 파라미터 부분에 설정하면 된다.
  • exchange는 request header, body를 HttpEntity<?>를 사용하여 설정한다.
  • RequestEntity<?>를 사용하여 url, HTTP method, header, body 까지 설정 가능하다.
  • response를 읽을 때 확실하게 정해진 Type이 있다면 exchange가 편할것 같다.
  • execute는 Callback 메서드를 생성해야하지만 exchange는 타입만 명시하면 되기 때문이다.
  • 사용 환경에 따라서 개발자가 편한대로 사용하면 될 것 같다.

나는 Request의 결과를 특정 type 형태로 받고 싶다!

  • XXXForObject를 사용하면 된다.

headers, body를 어떻게 생성하고 request 실행 메서드 파라미터로 사용하는지?

headers는 아래 코드로 생성할 수 있다

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);

HttpEntity<String> httpEntity = new HttpEntity<>(headers);

ResponseEntity<byte[]> responseEntity = restTemplate.exchange(downloadUrl, HttpMethod.GET, httpEntity, byte[].class);

body는 아래 코드로 생성할 수 있다

String body = "Request Body";

HttpEntity<String> httpEntity = new HttpEntity<>(body);

ResponseEntity<byte[]> responseEntity = restTemplate.exchange(downloadUrl, HttpMethod.GET, httpEntity, byte[].class);

headers + body는 아래 코드로 생성할 수 있다

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);

String body = "Request Body";

HttpEntity<String> httpEntity = new HttpEntity<>(body, headers);

ResponseEntity<byte[]> responseEntity = restTemplate.exchange(downloadUrl, HttpMethod.GET, httpEntity, byte[].class);

RestTemplate

  • 동기 방식으로 HTTP 요청을 할 수 있는 Java 기반 REST client
  • 간단한 template 메서드 API를 사용하여 HTTP 요청을 할 수 있다.
    • template 메서드는 JDK HttpURLConnection, Apache HttpComponents와 같은 기본 HTTP 클라이언트 라이브러리를 사용한다.
  • RestTemplate은 callback 메서드와 HttpMessageConverter를 커스터마이징 하여 사용할 수 있다. (보충 필요)
    • HttpMessageConverter : object를 HTTP request body로 마샬링할 수 있고, Response를 다시 object로 언마샬링 할 수 있다.
  • RestTemplate은 RESTful HTTP 요청을 만들기 위한 abstract method를 제공한다.
    • 내부적으로 Resttempalte은 Android HTTP client library를 활용한다.
    • 표준 JS2SE 기능은 SimpleClientHttpRequestFactory에 의해 제공
    • HttpClient는 HttpComponentsClientHttpRequestFacotry에 의해 제공
  • HTTP 요청을 처리하는 도중 에러가 발생하면 RestClientException 발생
    • ResponseErrorHandler를 구현하여 error를 핸들링할 수 있다.

RestTamplate 생성

  • RestTempalte을 new RestTemplate()으로 생성 시, message converter는 기본 HttpMessageConverters로 초기화 한다.
  • setXXX 메서드로 Error handling, message converter를 커스텀하게 설정할 수 있다.

RestTemplate 메서드 네이밍

  • RestTemplate 메서드의 네이밍 규칙
    • 첫 번째 부분 : 호출되는 HTTP 메서드
    • 두 번째 부분 : 반환되는 객체
    • getForObject() : GET을 수행하고, HTTP Response를 명시한 Object 유형으로 변환
    • postForLocation() : POST를 수행하고, 새로 생성된 객체를 찾을 수 있는 Response HTTP Location 헤더를 반환

RestTemplate template 메서드 종류

대부분의 템플릿 메서드는 내부적으로 execute() 메서드를 호출한다.

execute

  • 주어진 URI Template으로 HTTP method를 실행한다.

  • RequestCallback으로 request를 생성하고

  • ResponseExtrator로 response를 읽는다.

    @Nullable
    <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException;
    
    @Nullable
    <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Map<String, ?> uriVariables) throws RestClientException;
    
    @Nullable
    <T> T execute(URI url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException;

ClientHttpRequest

  • client-side HTTP request
  • ClientHttpRequestFactory에 의해 생성된다.
  • execute로 Http 요청을 진행하고, request에 대한 응답으로 ClientHttpResponse를 받는다.

RequestCallback

  • ClientHttpRequest에 대한 callback interface
    • request header, body 값을 설정할 수 있다.
  • ClientHttpRequest를 사용하고 RestTemplate.execute 메서드에 의해 호출된다.
  • request를 close 하는 것과 request error handling은 RestTemplate이 관리한다.

ResponseExtrator

  • ClientHttpRequest 요청 결과로 받은 ClientHttpResponse에서 데이터를 추출하는 작업을 수행.

uriVariables

  • uriTemplate의 queryString에 해당하는 값을 명시

    String uriTemplate = "http://localhost:8080?value={value}";
    
    Map<String, String> uriParamMap = new HashMap<String, String>();
    uriParamMap.put("value", "1");
    
    restTemplate.execute(uriTemplate, HttpMethod.GET, requestCallback, responseExtractor, uriParamMap);

exchange

  • 전달받은 URI template과 HTTP method로 http request 요청을 수행한다.
  • HttpEntity<?> requestEntity 파라미터로 request를 작성한다.
  • Class<T> responseType 파라미터로 request에 대한 reponse를 ReponseEntity<T>으로 반환한다.
  • ParameterizedTypeReference<T> responseType 파라미터로 response의 type을 다양하게 설정할 수 있다.

파라미터로 봤을 때는 execute와 달라보이지만 사실 내부 로직은 동일하다.

  • 결국 exeute() 메서드를 호출한다.
    @Override
    public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException {
        RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
        ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
        return nonNull(execute(url, method, requestCallback, responseExtractor, uriVariables));
    }

requestEntity 파라미터

  • requestEntity를 전달할 때 다양한 방법이 있다.

    • http header만 있는 경우

      ```java
      HttpHeaders headers = new HttpHeaders();
      headers.setContentType(MediaType.MULTIPART_FORM_DATA);
      
      HttpEntity<String> httpEntity = new HttpEntity<>(headers);
      
      ResponseEntity<byte[]> responseEntity = restTemplate.exchange(downloadUrl, HttpMethod.GET, httpEntity, byte[].class);
      ```
      
    • http body만 있는 경우

      ```java
      String body = "request body";
      
      ResponseEntity<byte[]> responseEntity = restTemplate.exchange(downloadUrl, HttpMethod.GET, body, byte[].class);
      ```
      
    • http header + body 있는 경우

      ```java
      HttpHeaders headers = new HttpHeaders();
      headers.setContentType(MediaType.MULTIPART_FORM_DATA);
      
      String body = "request body";
      
      HttpEntity<String> httpEntity = new HttpEntity<>(body, headers);
      
      ResponseEntity<byte[]> responseEntity = restTemplate.exchange(downloadUrl, HttpMethod.GET, httpEntity, byte[].class);
      ```
      
  • 전달받은 requestEntity, responseType으로 RequestCallback을 생성한다.

    • 이때 생성되는 RequestCallbackHttpEntityRequestCallback이다.
  • HttpEntityRequestCallback을 생성할 때 request의 headers, body가 설정되고 responseType이 설정된다.

    public HttpEntityRequestCallback(@Nullable Object requestBody, @Nullable Type responseType) {
        super(responseType);
        if (requestBody instanceof HttpEntity) {
            this.requestEntity = (HttpEntity<?>) requestBody;
        }
        else if (requestBody != null) {
            this.requestEntity = new HttpEntity<>(requestBody);
        }
        else {
            this.requestEntity = HttpEntity.EMPTY;
        }
    }
    • super(responseType)로 response를 읽을 때 어떤 타입으로 읽을지 설정한다.
      • 이후 RequsetCallback 인터페이스 doWithRequest 메서드에서 response를 등록된 messageConverters 사용하여 responseType으로 읽을 수 있는지 판단한다.

XXXForEntity

  • exchange 메서드와 동일하다

  • httpEntityCallback 메서드로 requestCallback을 생성하고

  • responseEntityExtractor 메서드로 ResponseExtractor<ResponseEntity<T>>를 만들어 response의 데이터를 추출한다.

    ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
    return nonNull(execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables));

XXXForObject

  • exchange 메서드와 거의 동일하다

  • httpEntityCallback 메서드로 requestCallback을 생성하고

  • HttpMessageConverterExtractor를 생성하여 response에서 데이터를 주어진 Type으로 추출한다.

    HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);
    return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
⚠️ **GitHub.com Fallback** ⚠️