· 오늘 공부한 것
RestTemplate으로 Get, Post 요청과 Header에 추가적인 정보를 전달할 때 exchange매서드 사용
Open API 네이버를 검색기능을 활용하여 실습
· 공부한 내용, 궁금한 내용, 부족한 내용
client에서 보통 서버로 요청을 해서 받은 데이터로 뭔가를 활용을 했다. 하지만 요청한 서버에서도 또 다른 서버로 요청을 보내서 응답을 받아 올 수 있다. 실습에서 client 서버와 server 서버를 만들었고 각 포트를 8080과 7070으로 사용했다. 그러면 Get과 Post 요청을 살펴보자.
Get 요청
1. 먼저 RestTemplate을 주입받는다.
private final RestTemplate restTemplate;
// RestTemplateBuilder의 build()를 사용하여 RestTemplate을 생성합니다.
public RestTemplateService(RestTemplateBuilder builder) {
this.restTemplate = builder.build();
}
2. 요청받은 검색어를 Query String 방식으로 Server 입장의 서버로 RestTemplate를 사용하여 요청받는다.
public ItemDto getCallObject(String query) {
// 요청 URL 만들기
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();
}
위와 같은 방식으로 다른 서버로 요청할 uri를 만들어서 보내면 데이터를 받아올 수 있는데 만약 받아올 데이터가 1개가 아니라 여러 개일 경우는 아래와 같이 사용한다.
public List<ItemDto> getCallList() {
// 요청 URL 만들기
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());
}
단품 조회와 다르게 여러 개일 경우 일단 String값 그대로 가져온다. 일단 sever 입장 서버의 ItemResponseDto가 어떤 형태인지를 보면 다음과 같다.
{
"items":[
{"title":"Mac","price":3888000},
{"title":"iPad","price":1230000},
{"title":"iPhone","price":1550000},
{"title":"Watch","price":450000},
{"title":"AirPods","price":350000}
]
}
그렇기에 String으로 넘어온 값을 다시 JSON 형태로 만들어 줘야 하기 때문에 아래와 같은 과정을 거쳤다.
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;
}
post 요청
위에서 주입은 했으니 다른 서버로 RestTemplate를 사용하여 요청하는 것은 아래와 같다.
public ItemDto postCall(String query) {
// 요청 URL 만들기
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();
}
여기서는 get에서는 첫 번째 uri 두 번째가 전달받은 데이터와 매핑하여 인스턴스화할 클래스의 타입이었는데 post요청의 경우 두 번째가 HTTP Body에 넣어줄 데이터이다.
그러면 Header에 정보를 추가하고 싶을 때 다음과 같이 exchange 매서드의 첫 번째 파라미터에 RequestEntity 객체를 만들어 전달해 주면 된다. 이 안에 uri, header, body의 정보를 모두 담아 전달할 수 있다.
public List<ItemDto> exchangeCall(String token) {
// 요청 URL 만들기
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());
}
Naver Open ApI
이번 실습에서 네이버 open api를 활용했는데 여기에서 제공하는 것들은 아래와 같다. 나는 이 중에서 검색기능을 사용하였다.
일단 사이트에서 애플리케이션을 로컬로 등록하는 과정을 거쳤다.
그리고 JSON 형태로 반환받기 위해 요청 URL은 아래에 있는 것을 사용했다.
curl "https://openapi.naver.com/v1/search/shop.json?query=%EC%A3%BC%EC%8B%9D&display=10&start=1&sort=sim" \
-H "X-Naver-Client-Id: {애플리케이션 등록 시 발급받은 클라이언트 아이디 값}" \
-H "X-Naver-Client-Secret: {애플리케이션 등록 시 발급받은 클라이언트 시크릿 값}" -v
query에 검색할 검색어가 들어가게 되고 요청 시 헤더에 애플리케이션 등록할 때 발급받은 아이디 값과 시크릿 값도 들어가야 한다.
그러면 위에서 사용한 RestTemplate으로 코드를 아래와 같이 구현하였다.
먼저 controller에서 NaverApiService를 주입한다.
@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);
}
}
그리고 service에서 네이버 검색 api를 보낸다.
@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) {
// 요청 URL 만들기
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();
ResponseEntity<String> responseEntity = restTemplate.exchange(requestEntity, String.class);
log.info("NAVER API Status Code : " + responseEntity.getStatusCode());
return fromJSONtoItems(responseEntity.getBody());
}
여기서 exchange 메서드를 사용해서 헤더에 아이디와 시크릿 값을 넣어서 보내주고 있다. 그리고 받아온 값이 String이므로 fromJSONtoItems 매서드로 변환하는 과정을 거쳐 itemDto 형태의 리스트로 값을 가져오고 있다.
· 오늘 서칭 한 자료
https://developers.naver.com/docs/serviceapi/search/shopping/shopping.md#%EC%87%BC%ED%95%91
· 느낀 점
- 만든 서버로 모든 요청을 해결하는 것이 아니라 외부 서버로 다시 요청을 해서 받아오는 형태로 개발해도 된다. (개발 범위의 확장)
- 이미 만들어져 있는 오픈 api를 활용해서 프로젝트 개발에 사용할 수 있을 거 같다.
- 특히 거의 모든 페이지에서 로그인의 경우 카카오, 네이버, 구글 로그인을 포함하고 있기 때문에 필수적으로 사용할 줄 알아야 한다고 느꼈다.
'Today I Learned' 카테고리의 다른 글
2023-11-27 TIL (0) | 2023.11.27 |
---|---|
2023-11-16 TIL (0) | 2023.11.16 |
2023-11-14 TIL (0) | 2023.11.14 |
2023-11-13 TIL (0) | 2023.11.13 |
2023-11-07 TIL (0) | 2023.11.07 |