RestTemplate

duckbill413·2023년 1월 21일
0

Spring boot

목록 보기
3/13
post-thumbnail

RestTemplate

Spring에서 지원하는 Rest 방식 API를 호출할 수 있는 Spring 내장 클래스

  • Spring 3.0 부터 지원하는 Spring의 HTTP 통신 템플릿
  • HTTP 요청 후 JSON, XML, String 과 같은 응답을 받을 수 있는 템플릿
  • Blocking I/O 기반의 동기방식을 사용하는 템플릿
  • RESTful 형식에 맞추어진 템플릿
  • Header, Content-Type등을 설정하여 외부 API호출
  • Server to Server 통신에 사용

RestTemplate 동작 원리

  1. 애플리케이션 내부에서 REST API에 요청하기 위해 RestTemplate의 메서드를 호출한다.

  2. RestTemplate은 MessageConverter를 이용해 java object를 request body에 담을 message(JSON etc.)로 변환한다. 메시지 형태는 상황에 따라 다름

  3. ClientHttpRequestFactory에서 ClientHttpRequest을 받아와 요청을 전달한다.

  4. 실질적으로 ClientHttpRequest가 HTTP 통신으로 요청을 수행한다.

  5. RestTemplate이 에러핸들링을 한다.

  6. ClientHttpResponse에서 응답 데이터를 가져와 오류가 있으면 처리한다.

  7. MessageConverter를 이용해 response body의 message를 java object로 변환한다.

  8. 결과를 애플리케이션에 돌려준다.

※ RestTemplate은 통신 과정을 ClientHttpRequestFactory(ClientHttpRequest, ClientHttpResponse)에 위임합니다. ClientHttpRequestFactory의 실체는 HttpURLConnection, Apache HttpComponents, HttpClient와 같은 HTTP Client

RestTemplate Method

메서드HTTP설명
getForObjectGET주어진 URL 주소로 HTTP GET 메서드로 객체의 결과를 반환받는다.
getForEntityGET주어진 URL 주소로 HTTP GET 메서드로 결과는 ResponseEntity로 반환받는다.
postForLocationPOSTPOST 요청을 보내고 결과로 헤더에 저장된 URI를 결과로 반환받는다.
postForObjectPOSTPOST 요청을 보내고 객체로 결과를 반환받는다.
postForEntityPOSTPOST 요청을 보내고 결과로 ResponseEntity로 받는다.
deleteDELETE주어진 URL 주소로 HTTP DELETE 메서드를 실행한다.
headForHeadersHEADER헤더의 모든 정보를 얻을 수 있으면 HTTP HEAD 메서드를 사용한다.
putPUT주어진 URL 주소로 HTTP PUT 메서드를 실행한다.
patchForObjectPATCH주어진 URL 주소로 HTTP PATCH 메서드를 실행한다.
optionsForAllowOPTIONS주어진 URL 주소에서 지원하는 HTTP 메서드를 조회한다.
exchangeanyHTTP 헤더를 새로 만들 수 있고 어떤 HTTP 메서드도 사용 가능하다.
executeanyRequest/Response callback을 수정할 수 있다.

RestTemplate 실습

Server

  • Header 정보 요청
    @PostMapping("/user/{userId}/name/{userName}/exchange")
    public User helloPostExchange(@RequestBody User user,
                                  @PathVariable int userId,
                                  @PathVariable String userName,
                                  @RequestHeader("x-auth") String auth) {
    log.info("userId: {}", userId);
    log.info("userName: {}", userName);
    log.info("x-auth: {}", auth);
    log.info("client req : {}", user);
        return user;
    }
    @RequestHeader 로 헤더를 요청할 수 있다.
  • 실무에서 사용되는 형태의 json 요청
    @PostMapping("/user/{userId}/name/{userName}/exchange/generic")
        public Req<User> genericExchange(
    //            HttpEntity<String> entity, // response 를 String 형태 그대로 보여준다.
                @RequestBody Req<User> user,
                @PathVariable int userId,
                @PathVariable String userName,
                @RequestHeader("x-auth") String auth) {
    //        log.info("req : {}", entity.getBody());
    log.info("userId: {}", userId);
    log.info("userName: {}", userName);
    log.info("x-auth: {}", auth);
    log.info("client req : {}", user);
    
            Req<User> response = new Req<>();
            response.setHeader(new Req.Header());
            response.setResBody(user.getResBody());
            return response;
        }
    • HttpEntity<String> entity, entity.getBody() 를 활용하면 어떤 통신이 이루어졌는지 String으로 확인할 수 있다.

      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      public class Req<T> {
          private Header header;
          private T resBody;
      
          @Data
          @AllArgsConstructor
          @NoArgsConstructor
          public static class Header{
              private String responseCode;
          }
      }
    • 내부 클래스에 대해서도 lombok을 설정해야 원활히 동작한다.

Client

  • Get Method를 이용한 API

    public UserResponse helloUserParams(){
        URI uri = UriComponentsBuilder
                .fromUriString("http://localhost:9090")
                .path("/api/server/hello/user/param")
                .queryParam("name", "duckbill")
                .queryParam("age", 9999)
                .encode()
                .build()
                .toUri();
    log.info("Uri : {}", uri);
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<UserResponse> result = restTemplate.getForEntity(uri, 
    																											UserResponse.class);
    
    log.info("status code: {}", result.getStatusCode());
    log.info("body: {}", result.getBody());
    
        return result.getBody();
    }
    • URI 클래스를 이용하여 uri를 만들어 준다.
    • queryParam 으로 query 값을 넣어준다.
    • RestTemplate, ResponseEntity를 활용
    • request는 restTemplate.getForEntity Method에서 이루어진다. (GET METHOD)
    • getStatusCode, getBody 등으로 response 정보를 확인할 수 있다.
  • Post Method를 이용한 API

    public UserResponse userPost(){
            // http://localhost:9090/api/server/user/{userId}/name/{userName}
            URI uri = UriComponentsBuilder
                    .fromUriString("http://localhost:9090")
                    .path("/api/server/user/{userId}/name/{userName}")
                    .encode()
                    .build()
                    .expand("100", "duckbill")
                    .toUri();
    
            log.info("Uri : {}", uri);
            UserRequest userRequest = new UserRequest("duckbill", 30);
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<UserResponse> result = restTemplate.postForEntity(uri, userRequest, 
    																																			UserResponse.class);
    
            log.info("status code: {}", result.getStatusCode());
            log.info("headers: {}", result.getHeaders());
            log.info("body: {}", result.getBody());
    
            return result.getBody();
        }
    • URI의 encode를 이용하여 pathVariable 값을 순서대로 채울 수 있다.
    • restTemplate.postForEntity로 post 메소드 실행
  • Post Method의 Header 이용하기 exchange() Method

    public Req<UserResponse> genericExchange(){
            URI uri = UriComponentsBuilder
                    .fromUriString("http://localhost:9090")
                    .path("/api/server/user/{userId}/name/{userName}/exchange/generic")
                    .encode(Charset.forName("UTF-8"))
                    .build()
                    .expand("100", "duckbill")
                    .toUri();
    
            log.info("Uri : {}", uri);
    
            Req<UserRequest> req = new Req();
            req.setHeader(new Req.Header());
            UserRequest userRequest = new UserRequest("duckbill", 30);
            req.setResBody(userRequest);
    
            RequestEntity<Req<UserRequest>> requestEntity = RequestEntity
                    .post(uri)
                    .contentType(MediaType.APPLICATION_JSON)
                    .header("x-auth", "abcd1234") // Header 추가 여러개 추가 가능
                    .body(req);
    
            RestTemplate restTemplate = new RestTemplate();
    
            ResponseEntity<Req<UserResponse>> result = restTemplate.exchange(requestEntity,
    																						 new ParameterizedTypeReference<>() {});
    
            return result.getBody();
        }
    • RequestEntity를 이용하여 api request를 만들어준다.
    • REST API Method, contentType, header, body등을 지정하여 reqeust를 만들어 줄 수 있다.
    • API 요청을 restTemplate.exchange를 이용하여 실행한다.
    • body에 여러 클래스가 들어있는 형태의 json을 수신하기 위해서는 new ParameterizedTypeReference 를 이용해서 objectMapping을 해주어야 가능하다.
    • URI encoding은 encode(Charset.forName("UTF-8")) 을 이용

    📖 클래스 mapping을 위해서 new ParameterizedTypeReference 사용

profile
같이 공부합시다~

0개의 댓글