본문 바로가기

백엔드 학습 과정/Section 3 [Spring MVC, JDBC, JPA, RestDo

#1-1. Rest Client

[Rest Client]

Rest API 서버에 HTTP 요청을 보낼 때 사용하는 클라이언트 툴혹은 클라이언트 라이브러리

 

*REST API

웹에서 사용되는 Data Resource HTTP URI로 표현하고, 해당 resource를 고유의 URI로 접근하는 방식

 

[RestTemplate]

HTTP 클라이언트 라이브러리들 중 하나를 이용해 다른 BackEnd 서버에 HTTP 요청을 보낼 때

간편히 보낼 수 있는 틀이 잡은 요청 가이드라인, Rest Client API.

 

[RestTemplate *사용방법*]

 

1. RestTemplate 클래스 생성.

public class RestClientExample01 {
    public static void main(String[] args) {
        // (1) 객체 생성
        RestTemplate restTemplate = 
                new RestTemplate(new (2) HttpComponentsClientHttpRequestFactory());
    }
}

RestTemplate 객체를 생성하기 위해선 (2)과 같이 RestTemplate 객체의 생성자로

HTTP 클라이언트 라이브러리 구현 객체를 전달해줘야 한다.

예제와 같은 구현체는 Apache HttpComponents 라이브러리를 사용.

 

Bundle.gradle dependencies 항목에 아래 코드 추가 필요.

implementation 'org.apache.httpcomponents:httpclient'

 

2. URI 생성

RestTemplate 객체를 생성했다면, HTTP Request를 전송할 Rest 엔드포인트의 URI를 지정해야한다.

public class RestClientExample01 {
    public static void main(String[] args) {
        // (1) 객체 생성
        RestTemplate restTemplate =
                new RestTemplate(new HttpComponentsClientHttpRequestFactory());

        // (2) URI 생성
        UriComponents uriComponents =
                UriComponentsBuilder
                        (a).newInstance()
                        (b).scheme("http")
                        (c).host("worldtimeapi.org")
//                        (d).port(80)
                        (e).path("/api/timezone/{continents}/{city}")
                        (f).encode()
                        (g).build();
        (h) URI uri = uriComponents.expand("Asia", "Seoul").toUri();
    }
}

UriComponentsBulder를 이용해 UriComponents 객체를 생성 후 HTTP Request 엔드포인트 URI 생성.

 

(a) .newInstance() : UriComponentsBuilder 객체를 생성

(b) .scheme() : URI scheme 설정

(c) .host() : 호스트의 정보 입력

(d) .port() : 디폴트 값은 80이므로, 80포트를 사용하는 호스트라면 생략 가능.

(e) .path() : URI 경로 입력. 예시에서는 {continents}, {city} 두 개의 템플릿 변수 존재.

이 두 변수는 (h)에서.expand() 메서드 파라미터의 문자열에 채워진다. {continents} => Asia, {city}=> Seoul

(f) .encode() : URI에 사용된 템플릿 변수들을 인코딩해준다.

                  인코딩: non-ASCII 문자와 URI에 적절하지 않은 문자를 Percent Encoding 한다는 의미.

(g) .build() : UriComponents 객체를 생성하는 역할.

(h) .expand() : 파라미터로 입력한 값을 URI 경로에 존재하는 템플릿 변수들의 값으로 대체. (e) 참조.

(h) .toUri() : URI 객체를 생성. .build()와 비슷한 역할.

 

3. 요청 전송

 

A. getForObject() 이용하여 문자열 응답 데이터 전달 받기

 

public class RestClientExample01 {
    public static void main(String[] args) {
        // (1) 객체 생성
        RestTemplate restTemplate =
                new RestTemplate(new HttpComponentsClientHttpRequestFactory());

        // (2) URI 생성
        UriComponents uriComponents =
                UriComponentsBuilder
                        .newInstance()
                        .scheme("http")
                        .host("worldtimeapi.org")
//                        .port(80)
                        .path("/api/timezone/{continents}/{city}")
                        .encode()
                        .build();
        URI uri = uriComponents.expand("Asia", "Seoul").toUri();

        // (3) Request 전송
        String result = restTemplate.(a)getForObject((b)uri, (c)String.class);

        System.out.println(result);
    }
}

 

(a) getForObject( URI uri, Class<T> responseType) : HTTP Get요청을 통해 서버의 리소스를 조회.

(b) uri : Request를 전송할 엔드포인트 ((2)에서 생성한 UriComponents 객체에 추가 생성된

멤버 변수를 .expand()메서드의 파라미터로 대체하여 생성한 객체 URI uri) URI 객체

(c) String.class : 응답으로 전달 받을 클래스의 타입을 지정.

 

 

B. getForObject()를 이용하여 원하는 정보만 별도의 클래스를 생성하여(커스텀 클래스타입) 응답으로 받기

public class RestClientExample02 {
    public static void main(String[] args) {
        // (1) 객체 생성
        RestTemplate restTemplate =
                new RestTemplate(new HttpComponentsClientHttpRequestFactory());

        // (2) URI 생성
        UriComponents uriComponents =
                UriComponentsBuilder
                        .newInstance()
                        .scheme("http")
                        .host("worldtimeapi.org")
//                        .port(80)
                        .path("/api/timezone/{continents}/{city}")
                        .encode()
                        .build();
        URI uri = uriComponents.expand("Asia", "Seoul").toUri();

        // (3) Request 전송. WorldTime 클래스로 응답 데이터를 전달 받는다.
        WorldTime worldTime = restTemplate.getForObject(uri, WorldTime.class);

        System.out.println("# datatime: " + worldTime.getDatetime());
        System.out.println("# timezone: " + worldTime.getTimezone());
        System.out.println("# day_of_week: " + worldTime.getDay_of_week());
    }
}

응답 데이터를 WorldTime 클래스 객체로 전달받고 있다.

public class WorldTime {
    private String datetime;
    private String timezone;
    private int day_of_week;

    public String getDatetime() {
        return datetime;
    }

    public String getTimezone() {
        return timezone;
    }

    public int getDay_of_week() {
        return day_of_week;
    }
}

원하는 변수들만 멤버로 선언하고 get 메소드 작업을 한다.

(주의사항 : JSON property 이름과, 클래스의 멤버변수 이름, getter 메서드의 이름이 동일해야한다.

 

 

C. getForEntity()를 사용한 Response Body(바디, 컨텐츠) + Header(헤더) 정보 전달 받기

public class RestClientExample02 {
    public static void main(String[] args) {
        // (1) 객체 생성
        RestTemplate restTemplate =
                new RestTemplate(new HttpComponentsClientHttpRequestFactory());

        // (2) URI 생성
        UriComponents uriComponents =
                UriComponentsBuilder
                        .newInstance()
                        .scheme("http")
                        .host("worldtimeapi.org")
//                        .port(80)
                        .path("/api/timezone/{continents}/{city}")
                        .encode()
                        .build();
        URI uri = uriComponents.expand("Asia", "Seoul").toUri();

        // (3) Request 전송. ResponseEntity로 헤더와 바디 정보를 모두 전달 받을 수 있다.
        (a) ResponseEntity<WorldTime> response =
                restTemplate.getForEntity(uri, WorldTime.class);

        System.out.println("# datatime: " + (b) response.getBody().getDatetime());
        System.out.println("# timezone: " + response.getBody().getTimezone()());
        System.out.println("# day_of_week: " + response.getBody().getDay_of_week());
        System.out.println("# HTTP Status Code: " + response.getStatusCode());
        System.out.println("# HTTP Status Value: " + response.getStatusCodeValue());
        System.out.println("# Content Type: " + response.getHeaders().getContentType());
        System.out.println(response.(c) getHeaders().entrySet());
    }
}

getForEntity() 메서드를 사용해 헤더 정보, 바디 정보를 전달 받고 있다.

(a) : 응답 데이터는 ResponseEntity 클래스로 래핑되어 전달되며,

(b) : ResponseEntity 객체에 .getBody().getHeaders() 메서드로 정보를 전달받고 있다.

(c) : 응답으로 전달되는 모든 헤더 정보를 보고 싶다면 entrySet() 메소드를 활용.

 

 

D. exchange()를 사용한 응답 데이터 받기

public class RestClientExample03 {
    public static void main(String[] args) {
        // (1) 객체 생성
        RestTemplate restTemplate =
                new RestTemplate(new HttpComponentsClientHttpRequestFactory());

        // (2) URI 생성
        UriComponents uriComponents =
                UriComponentsBuilder
                        .newInstance()
                        .scheme("http")
                        .host("worldtimeapi.org")
//                        .port(80)
                        .path("/api/timezone/{continents}/{city}")
                        .encode()
                        .build();
        URI uri = uriComponents.expand("Asia", "Seoul").toUri();

        // (3) Request 전송. exchange()를 사용한 일반화 된 방식
        ResponseEntity<WorldTime> response =
                restTemplate.(a) exchange((b)uri,
                        (c)HttpMethod.GET,
                        (d)null,
                        (e)WorldTime.class);

        System.out.println("# datatime: " + response.getBody().getDatetime());
        System.out.println("# timezone: " + response.getBody().getTimezone());
        System.out.println("# day_of_week: " + response.getBody().getDay_of_week());
        System.out.println("# HTTP Status Code: " + response.getStatusCode());
        System.out.println("# HTTP Status Value: " + response.getStatusCodeValue());
    }
}

 

(a) exchange(URI uri, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType)

getForObject(), getForEntity()와는 달리 exchange() 메서드는

HTTP Method, RequestEntity, ResponseEntity를 직접 지정하여

HTTP Request를 전송할 수 있는 가장 일반적 방법이다.

(b) URI url : Request를 전송할 엔드포인트( 2번에서 생성한 UriCompoents 객체에 추가 생성된 멤버 변수를 .expand() 메서드의 파라미터로 대체하며 생성한 URI 객체)를 지정.

(c) HTTP Method 타입을 지정

(d) HttpEntity 객체를 지정, HttpEntity 객체를 통해 헤더 및 바디, 파라미터 등을 설정.

(e) 응답으로 전달 받을 클래스의 타입을 지정

 

 

<핵심 포인트>

웹 브라우저웹 서버로부터 HTML 컨텐츠를 제공받는 클라이언트 중 하나이다.

클라이언트, 서버의 역할은 이용할 리소스의 위치에 따라 동적인 존재이다.

Rest Client Rest API 서버에 HTTP 요청을 보낼 수 있는 클라이언트 툴, 클라이언트 라이브러리 이다.

RestTemplate : 다른 원격지에 있는 BackEnd Server HTTP 요청을 보낼 수 있도록 정한 Rest Client API.

RestTemplate 사용 단계

1. RestTemplate 객체 생성.

2. HTTP 요청을 전송할 엔드포인트의 URI 객체 생성.

3. getForObject(), getForEntity(), exchange() 메소드를 이용해 HTTP 요청을 전송.

RestTemplate 기능 예시 : 결제서비스, 카카오톡 등의 메시징 서비스, Google Map등 지도 서비스,

공공 데이터 포털 OPEN API, 기타 원격지 API 서버와의 통신