
저번 'WebClient 사용해 외부 API 호출하기'의 연장선이다. WebClient로 외부 API를 호출하고 Json 형태의 response를 받았다.
String url = "https://pixabay.com/api/";
String searchKeyword = country.toString().concat(" ").concat(city.toString());
WebClient webClient = WebClient.create(url);
String response = webClient.get()
.uri(uriBuilder -> uriBuilder
.queryParam("q", searchKeyword)
.queryParam("lang","ko")
.queryParam("key", apiKey)
.build())
.retrieve()
.bodyToMono(String.class)
.block();
API 호출 시 결과는 아래처럼 나타난다.
{
"total": 193,
"totalHits": 193,
"hits": [
{
"id": 2014618,
"pageURL": "https://pixabay.com/photos/japan-street-night-osaka-asia-2014618/",
"type": "photo",
"tags": "japan, street, night",
"previewURL": "https://cdn.pixabay.com/photo/2017/01/28/02/24/japan-2014618_150.jpg",
"previewWidth": 150,
"previewHeight": 99,
"webformatURL": "https://pixabay.com/get/g128b7c43a03a139f86f88720b1531d28b306c82c885a09347fb4b650ac4227f73432a6fd59baeb41f98bb6828b4de784dafe69ec2ddbd4fa7625172ec081fb43_640.jpg",
"webformatWidth": 640,
"webformatHeight": 425,
"largeImageURL": "https://pixabay.com/get/g45643b083f9740acb8780c1e7fb82e0d794e23009b09e211c5eadb74cd1da808c144afeddecd6cf4b3636fc868dae778f6d0676da651b4ab552de7fa477c441d_1280.jpg",
"imageWidth": 2048,
"imageHeight": 1362,
"imageSize": 752538,
"views": 862521,
"downloads": 665922,
"collections": 1865,
"likes": 1432,
"comments": 168,
"user_id": 4385858,
"user": "MasashiWakui",
"userImageURL": "https://cdn.pixabay.com/user/2017/01/28/02-10-45-719_250x250.jpg"
},
...
위 response에서 필요한 필드는 결과 중 첫 번째 사진의 'largeImageUrl' 하나이다.
원래 json 형태의 response를 받아서 사용하는 방법으로는 애초에 받을 때부터 response 필드들에 맞는 DTO class를 생성해서 매핑된 결과를 받는 것이 있다. 하지만 난 저 모든 결과가 필요한 것도 아니고 딱 하나의 필드만 사용하기 때문에 class를 만드는 것은 손해라고 생각했다.
그래서 라이브러리 추가만 하면 쉽게 사용할 수 있는 json-simple 라이브러리를 사용하여 파싱했다.
json 형태의 데이터를 쉽게 다룰 수 있도록 파싱하는 메서드를 제공한다.
먼저 build.gradle에 json-simple 라이브러리 의존성을 추가해주자.
//json-simple
implementation group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1'
JSONParser 객체를 생성하고 json 형태의 response를 parse()에 넣어 파싱한다. 파싱에 실패한 경우, ParserException이 터지므로 try-catch로 묶었다. object가 파싱한 결과가 들어갈 JSONObject 객체이다.
JSONParser parser = new JSONParser();
JSONObject object;
try {
object = (JSONObject)parser.parse(response);
} catch (ParseException e) {
throw new RuntimeException(e);
}
이제 내가 원하는 첫 번째 결과의 largeImageURL만 뽑아내면 된다!
JSONArray hits = (JSONArray)object.get("hits"); // "hits" 키의 결과들
JSONObject hitBody = (JSONObject)hits.get(0); // "hits"의 첫 번째 사진
String result = (String)hitBody.get("largeImageURL"); // hitBody의 largeImageURL 결과
내가 사용하는 Stock Image API를 테스트 해보니까 사진 데이터가 좀 다양하지 않아서 그런지 몇몇 검색어에 대해서는 hits 결과가 하나도 없는 경우가 있었다. 그래서 검색 결과가 없을 땐 null을 return해 프론트쪽에서 대체 이미지를 넣기로 했다.
전체 코드는 아래와 같다.
private static String parseResponseToImageUrl(String response) {
JSONParser parser = new JSONParser();
JSONObject object;
try {
object = (JSONObject)parser.parse(response);
} catch (ParseException e) {
throw new RuntimeException(e);
}
try{
JSONArray hits = (JSONArray)object.get("hits");
JSONObject hitBody = (JSONObject)hits.get(0);
return (String)hitBody.get("largeImageURL");
} catch (RuntimeException e) {
return null;
}
}
나는 위에 WebClient로 외부 API 호출한 곳에서 parseResponseToImageUrl() 메서드를 호출하여 결과를 사용했다. json-simple 라이브러리 사용하니까 적은 수의 결과를 사용하고자 할 땐 아주 유용하게 쓸만 할 것 같다!