내일배움캠프

[내일배움캠프] RestTemplate, Open API

munsik22 2026. 4. 9. 14:17

🧩 RestTemplate이란?

  • 정의: 서버(Client 입장)에서 다른 서버로 간편하게 요청할 수 있도록 Spring에서 제공하는 기능
  • 프로젝트 생성
    • 클라이언트: spring-resttemplate-client, 의존성 Spring Web, Lombok 추가
    • 서버: spring-resttemplate-server, 의존성 Spring Web, Lombok 추가
  • [Server] application.properties: 포트번호 변경
server.port=7070
  • Client 입장 서버: RestTemplateController, ItemDto, User, RestTemplateService
  • Server 입장 서버: ItemController, UserRequestDto, ItemResponseDto, Item, ItemService

GET 요청

  • [Client] RestTemplateService
private final RestTemplate restTemplate;

public RestTemplateService(RestTemplateBuilder builder) {
    this.restTemplate = builder.build();
}

public ItemDto getCallObject(String query) {
    URI uri = UriComponentsBuilder
            .fromUriString("http://localhost:7070")
            .path("/api/server/get-call-obj")
            .queryParam("query", query)
            .encode()
            .build()
            .toUri();
    log.info("uri = " + uri);

    ResponseEntity<ItemDto> responseEntity = restTemplate.getForEntity(uri, ItemDto.class);

    log.info("statusCode = " + responseEntity.getStatusCode());

    return responseEntity.getBody();
}

  • 🚨 만약 위와 같은 문제가 발생했다면, build.gradle에 다음 의존성을 추가해보자.
implementation 'org.springframework.boot:spring-boot-starter-restclient'
  • import는 다음과 같이 하면 된다.
import org.springframework.boot.restclient.RestTemplateBuilder;
  • [Server] ItemSerivice
public Item getCallObject(String query) {
    for (Item item : itemList) {
        if(item.getTitle().equals(query)) {
            return item;
        }
    }
    return null;
}
  • 아이템 하나 받아오는 테스트

2026-04-09T12:04:02.027+09:00  INFO 13260 --- [spring-resttemplate-client] [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2026-04-09T12:04:02.027+09:00  INFO 13260 --- [spring-resttemplate-client] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2026-04-09T12:04:02.028+09:00  INFO 13260 --- [spring-resttemplate-client] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
2026-04-09T12:04:02.069+09:00  INFO 13260 --- [spring-resttemplate-client] [nio-8080-exec-1] c.s.s.service.RestTemplateService        : uri = http://localhost:7070/api/server/get-call-obj?query=Mac
2026-04-09T12:04:02.328+09:00  INFO 13260 --- [spring-resttemplate-client] [nio-8080-exec-1] c.s.s.service.RestTemplateService        : statusCode = 200 OK
  • [Client] build.gradle
implementation 'org.json:json:20231013'
  • [Client] RestTemplateService
public List<ItemDto> getCallList() {
    URI uri = UriComponentsBuilder
            .fromUriString("http://localhost:7070")
            .path("/api/server/get-call-list")
            .encode()
            .build()
            .toUri();
    log.info("uri = " + uri);

    ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);

    log.info("statusCode = " + responseEntity.getStatusCode());
    log.info("Body = " + responseEntity.getBody());

    return fromJSONtoItems(responseEntity.getBody());
}

public List<ItemDto> fromJSONtoItems(String responseEntity) {
    JSONObject jsonObject = new JSONObject(responseEntity);
    JSONArray items  = jsonObject.getJSONArray("items");
    List<ItemDto> itemDtoList = new ArrayList<>();

    for (Object item : items) {
        ItemDto itemDto = new ItemDto((JSONObject) item);
        itemDtoList.add(itemDto);
    }

    return itemDtoList;
}
  • [Client] ItemDto
public ItemDto(JSONObject itemJson) {
    this.title = itemJson.getString("title");
    this.price = itemJson.getInt("price");
}
  • [Server] ItemService
public ItemResponseDto getCallList() {
    ItemResponseDto responseDto = new ItemResponseDto();
    for (Item item : itemList) {
        responseDto.setItems(item);
    }
    return responseDto;
}
  • 아이템 여러 개 받아오는 테스트

2026-04-09T12:13:35.642+09:00  INFO 12504 --- [spring-resttemplate-client] [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2026-04-09T12:13:35.642+09:00  INFO 12504 --- [spring-resttemplate-client] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2026-04-09T12:13:35.643+09:00  INFO 12504 --- [spring-resttemplate-client] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
2026-04-09T12:13:35.683+09:00  INFO 12504 --- [spring-resttemplate-client] [nio-8080-exec-1] c.s.s.service.RestTemplateService        : uri = http://localhost:7070/api/server/get-call-list
2026-04-09T12:13:35.864+09:00  INFO 12504 --- [spring-resttemplate-client] [nio-8080-exec-1] c.s.s.service.RestTemplateService        : statusCode = 200 OK
2026-04-09T12:13:35.864+09:00  INFO 12504 --- [spring-resttemplate-client] [nio-8080-exec-1] c.s.s.service.RestTemplateService        : Body = {"items":[{"title":"Mac","price":3888000},{"title":"iPad","price":1230000},{"title":"iPhone","price":1550000},{"title":"Watch","price":450000},{"title":"AirPods","price":350000}]}

POST 요청

  • [Client] RestTemplateService
public ItemDto postCall(String query) {
    URI uri = UriComponentsBuilder
            .fromUriString("http://localhost:7070")
            .path("/api/server/post-call/{query}")
            .encode()
            .build()
            .expand(query)
            .toUri();
    log.info("uri = " + uri);

    User user = new User("Robbie", "1234");

    ResponseEntity<ItemDto> responseEntity = restTemplate.postForEntity(uri, user, ItemDto.class);

    log.info("statusCode = " + responseEntity.getStatusCode());

    return responseEntity.getBody();
}
  • [Server] ItemService
public Item postCall(String query, UserRequestDto userRequestDto) {
    System.out.println("userRequestDto.getUsername() = " + userRequestDto.getUsername());
    System.out.println("userRequestDto.getPassword() = " + userRequestDto.getPassword());

    return getCallObject(query);
}
  • PathVariable 테스트

클라이언트 로그 서버 로그

exchange

RestTemplate으로 요청을 보낼 때 Header에 특정 정보를 같이 전달 하고 싶다면 어떻게 해야 할까?

  • [Client] RestTemplateService
public List<ItemDto> exchangeCall(String token) {
    URI uri = UriComponentsBuilder
            .fromUriString("http://localhost:7070")
            .path("/api/server/exchange-call")
            .encode()
            .build()
            .toUri();
    log.info("uri = " + uri);

    User user = new User("Robbie", "1234");

    RequestEntity<User> requestEntity = RequestEntity
            .post(uri)
            .header("X-Authorization", token)
            .body(user);

    ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);

    return fromJSONtoItems(responseEntity.getBody());
}
  • [Server] ItemService
public ItemResponseDto exchangeCall(String token, UserRequestDto requestDto) {
    System.out.println("token = " + token);
    System.out.println("requestDto.getUsername() = " + requestDto.getUsername());
    System.out.println("requestDto.getPassword() = " + requestDto.getPassword());

    return getCallList();
}

클라이언트 로그 서버 로그

🧩 Open API

Naver Open API

네이버에서는 다양한 오픈 API들을 제공한다.

 

네이버 오픈 API 목록 - INTRO

네이버 오픈 API 목록 NAVER Developers - API 소개 네이버 오픈API 목록 및 안내입니다. 네이버 오픈 API 목록 API명 설명 호출제한 검색 네이버 블로그, 이미지, 웹, 뉴스, 백과사전, 책, 카페, 지식iN 등 검

developers.naver.com

API명 설명 호출제한
검색 네이버 블로그, 이미지, 웹, 뉴스, 백과사전, 책, 카페, 지식iN 등 검색 25,000회/일
네이버 로그인 외부 사이트에서 네이버 로그인 기능 구현 없음
네이버 회원 프로필 조회 네이버 회원 이름, 이메일 주소, 휴대전화번호, 별명, 성별, 생일, 연령대, 출생연도, 프로필 조회 없음
CLOVA Face Recognition 입력된 사진을 입력받아 얼굴윤곽/부위/표정/유명인 닮음도를 리턴 1,000건/일
데이터랩(검색어트렌드) 통합검색어 트렌드 조회 1,000회/일
데이터랩(쇼핑인사이트) 쇼핑인사이트 분야별 트렌드 조회 1,000회/일
캡차(이미지) 자동 입력 방지용 보안 이미지 생성 및 입력값 비교 1,000회/일
캘린더 로그인한 사용자 캘린더에 일정 추가 가능 5,000회/일
카페 특정 네이버 카페 가입하기 50회/일
카페 네이버 회원이 가입한 카페 게시판에 글 쓰기 200회/일
공유하기 네이버 블로그, 카페 공유하기 없음
  • NAVER Developers에서 애플리케이션 등록하기

  • 우리가 사용할 검색 API에 대한 정보는 아래 문서에서 더 자세하게 확인할 수 있다.
 

검색 > 쇼핑 - Search API

검색 > 쇼핑 쇼핑 검색 개요 개요 검색 API와 쇼핑 검색 개요 검색 API는 네이버 검색 결과를 뉴스, 백과사전, 블로그, 쇼핑, 웹 문서, 전문정보, 지식iN, 책, 카페글 등 분야별로 볼 수 있는 API입니다

developers.naver.com

  • Postman 테스트: 발급받은 Client ID와 Client Secret을 Headers에 넣어야 한다.

  • [Client] NaverApiController
@RestController
@RequestMapping("/api")
public class NaverApiController {

    private final NaverApiService naverApiService;

    public NaverApiController(NaverApiService naverApiService) {
        this.naverApiService = naverApiService;
    }

    @GetMapping("/search")
    public List<ItemDto> searchItems(@RequestParam String query)  {
        return naverApiService.searchItems(query);
    }
}
  • [Client] NaverApiService
@Slf4j(topic = "NAVER API")
@Service
public class NaverApiService {

    private final RestTemplate restTemplate;

    public NaverApiService(RestTemplateBuilder builder) {
        this.restTemplate = builder.build();
    }

    public List<ItemDto> searchItems(String query) {
        URI uri = UriComponentsBuilder
                .fromUriString("https://openapi.naver.com")
                .path("/v1/search/shop.json")
                .queryParam("display", 15)
                .queryParam("query", query)
                .encode()
                .build()
                .toUri();
        log.info("uri = " + uri);

        RequestEntity<Void> requestEntity = RequestEntity
                .get(uri)
                .header("X-Naver-Client-Id", "Client-Id")
                .header("X-Naver-Client-Secret", "Client-Secret")
                .build();

        RequestEntity<Void> requestEntity = builder.build();

        ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);

        log.info("NAVER API Status Code : " + responseEntity.getStatusCode());

        return fromJSONtoItems(responseEntity.getBody());
    }

    public List<ItemDto> fromJSONtoItems(String responseEntity) {
        JSONObject jsonObject = new JSONObject(responseEntity);
        JSONArray items  = jsonObject.getJSONArray("items");
        List<ItemDto> itemDtoList = new ArrayList<>();

        for (Object item : items) {
            ItemDto itemDto = new ItemDto((JSONObject) item);
            itemDtoList.add(itemDto);
        }

        return itemDtoList;
    }
}

???

  • [Client] NaverApiService 수정
private final String clientId = System.getenv("NAVER_CLIENT_ID");
private final String clientSecret =  System.getenv("NAVER_CLIENT_SECRET");

/* ... */

//        RequestEntity<Void> requestEntity = RequestEntity
//                .get(uri)
//                .header("X-Naver-Client-Id", "Client-Id")
//                .header("X-Naver-Client-Secret", "Client-Secret")
//                .build();

RequestEntity<Void> requestEntity = RequestEntity
        .get(uri)
        .headers(headers -> {
            headers.add("X-Naver-Client-Id", clientId);
            headers.add("X-Naver-Client-Secret", clientSecret);
        })
        .build();