🧩 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();

'내일배움캠프' 카테고리의 다른 글
| [내일배움캠프] 단위 테스트와 통합 테스트 (0) | 2026.04.10 |
|---|---|
| [내일배움캠프] 카카오 소셜 로그인 구현 (0) | 2026.04.10 |
| [내일배움캠프] 필터, Spring Security, Validation (0) | 2026.04.08 |
| [내일배움캠프] JWT을 사용한 회원가입과 로그인 구현 (0) | 2026.04.08 |
| [내일배움캠프] Bean 수동 등록, 쿠키와 세션 (0) | 2026.04.07 |



