Spring, RestTemplate으로 REST 클라이언트 구현하기

개요

웹의 시대가 열린지는 오래되었지만 REST API가 본격적으로 유행한지는 얼마 되지 않았다. 안타깝게도 국내는 비즈니스 로직 구현에만 초점을 맞추어 GET, POST 메써드의 구분 없이 API 요청을 허용한다거나(심지어 POST 요청에 쿼리 스트링을 담기도 한다.) 상태 코드를 사용하지 않고 무조건 200 응답 후 바디에 독자적인 코드를 재정의하는 등 HTTP 스펙의 권고사항을 무시한 API 개발이 너무나도 흔한 상황이다. 그럼에도 REST는 가독성, 유지보수성 등을 고려했을 때 꼭 필요한 설계 철학이다.(세계 최대의 커뮤니티 reddit 또한 REST API를 제공한다.) 이번 글에서는 이러한 REST API를 이용(소비)하는 클라이언트로서 RestTemplate의 사용 예를 설명하고자 한다.

라이브러리 종속성 추가

dependencies {
    compile group: 'org.springframework', name: 'spring-web', version: '4.2.6.RELEASE'
    compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.7.4'
    compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.7.4'
    compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.7.4'
    compile group: 'org.projectlombok', name: 'lombok', version: '1.16.8'
}
  • RestTemplate를 사용하기 위해 spring-web 아티팩트를 추가하였다.

  • RestTemplatePOJO-JSON 상호 변환시 기본값으로 Jackson 라이브러리를 사용한다. Jackson이 정상적으로 동작하려면 jackson-core, jackson-databind, jackson-annotations 3개 아티팩트를 추가해야 한다.

  • 만약 Jackson을 추가하지 않고 Gson을 추가하면 RestTemplateGson을 대신 사용한다. 어떤 HttpMessageConverter 구현 클래스를 등록하느냐의 차이로 MappingJackson2HttpMessageConverter, GsonHttpMessageConverter가 이 역할을 수행하며 RestTemplate 오브젝트 생성시 생성자로 명시적인 전달이 가능하다.

  • 만약 Spring Boot 기반의 프로젝트로 spring-boot-starter-web 아티팩트를 추가한 상태라면 위에 열거한 아티팩트를 추가할 필요가 없다. 모두 포함되어 있기 때문이다.(Gson은 따로 추가해야 한다.)

  • lombok 아티팩트 추가는 필수가 아닌 선택이다. LombokPOJO 작성시 반복적이고 지루한 RequiredArgsConstructor, Getter, Setter, ToString 메써드 작성을 자동화 해준다.(적지 않은 수의 국내 개발자들 이 작업이 귀찮아 POJO 대신 Map을 사용하는데 이는 Java가 가진 많은 장점을 포기하는 것이다.)

HTML GET 요청

단순한 HTML 응답을 받는 예이다.

HttpHeaders header = new HttpHeaders();
header.add(HttpHeaders.ACCEPT, MediaType.TEXT_HTML_VALUE);
ResponseEntity<String> response = new RestTemplate().exchange("http://www.naver.com/", HttpMethod.GET, new HttpEntity(header), String.class);

JSON GET 요청

에코 응답을 제공하는 JSON Test API를 사용하여 예를 작성해보겠다. JSON GET 요청에 앞서 응답을 받을 POJO 클래스를 구현한다. 아래 HeadersResponse 클래스는 JSON 응답을 담는 역할을 한다.

@Data
public class HeadersResponse {

    @JsonProperty("Accept-Language")
    private String acceptLanguage;

    @JsonProperty("Host")
    private String host;

    @JsonProperty("User-Agent")
    private String userAgent;

    @JsonProperty("Accept")
    private String accept;
}
  • 앞서 언급한 Lombok을 이용하여 POJO 구현시 반복적인 메써드의 작성을 제거했다. 클래스 레벨에 @Data를 명시하면 모든 것을 컴파일 시점에 대신 생성해준다.
  • @JsonPropertyPOJO-JSON 상호변환시 정확한 멤버 변수에 맵핑해주는 역할을 한다. Jackson이 제공하는 기능으로 Gson을 사용한다면 Gson이 제공하는 기능을 사용해야 한다.

작성된 POJO을 이용한 요청 예이다.

HttpHeaders header = new HttpHeaders();
header.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_UTF8_VALUE);
ResponseEntity<HeadersResponse> response = new RestTemplate().exchange("http://headers.jsontest.com/", HttpMethod.GET, new HttpEntity(header), HeadersResponse.class);

참고 글

저작자 표시 비영리 동일 조건 변경 허락
신고