프로젝트/LunchPick

01. kakao API 호출, git에 API key 숨기기 ( 스프링 )

Yanoo 2021. 12. 18. 19:22
728x90
반응형

프로젝트를 진행하면서 느낀점이나 해결했던 과정을 기록하기 위해 시작한다.

 

🎨 패키지 정리

처음 작업은 패키지 정리였는데, 카카오 API 요청을 어디서 할지였다.

일단 repository는 DB와 연관된 처리를 할 때이므로 제외시키고,

service냐 controller냐였는데, 회사 동기의 조언이나 다른 블로그 글들을 보고 service안에 externalAPI라는 패키지를 만들자는 결론을 내렸다.

이렇게 결론을 내리게된 이유는 API 요청 방법이 달라질 수 있고 다른 API들을 사용할 경우 분리해서 관리하기 쉽겠다고 생각을 해서이다.

이런식으로 준비를 하고 카카오 API 요청을 해보자. 요청을 하기 전에 git을 사용하므로 API 키 부터 숨겨야 한다.


🔑 API key 숨기기

일단 나는 카카오 API를 사용할 예정인데 거기서 키워드로 장소 검색하기 라는 API이다.

https://developers.kakao.com/docs/latest/ko/local/dev-guide#search-by-keyword

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

내 애플리케이션에 들어가보면

이런 API 키가 나오는데 API 사용을 위해서 필수로 사용해야 하고 다른사람이 이 키를 통해서 사용할 수 있으니 숨겨야 한다. 유료 API 호출을 사용할 경우 호출 수 제한등으로 다른 사람들이 사용할 수 있으니 숨겨야 하는 것이다.

 

이제 스프링으로 가서 resources안에 application-API-KEY.properties 라는 파일을 만든다.

그리고 내 애플리케이션에 적혀있는 REST API key가 123456이라고 한다면

application-API-KEY.properties 파일 안에 kakao_id = 123456이라고 적으면 된다. 즉, kakao_key = 자신의 REST API 키

그 다음 나는 yml을 사용하므로 application.yml에

이렇게 추가해주는데, application.properties를 사용하더라도 그냥 spring.profiles.include=API-KEY 라고 적으면 될듯(?)

파일이름에 API-KEY라는 문자가 들어가는 파일도 관리한다? 라고 생각하면 될듯.

그리고 .gitignore 파일에

src/main/resources/application-API-KEY.properties

를 추가해 준다.

그리고 이런식으로 사용하면 된다. 출력해보면 API 키를 받은 것을 확인할 수 있을것이다.

이제 Kakao API 를 호출해보자.


🎈 kakao API 호출

일단 오늘의 목표는 서울 시청의 100m 이내의 맛집을 검색을 목표로 잡았다.

아까 언급한 https://developers.kakao.com/docs/latest/ko/local/dev-guide#search-by-keyword

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

API를 사용할 것인데, 정보를 봐보면

나는 JSON으로 받을 것이고, GET 형식으로 요청하면 된다.

그리고 헤더인데 Host는 어차피

https://dapi.kakao.com/v2/local/search/keyword.JSON?

이런식으로 요청할테니 Host는 따로 설정 안해줘도 되고 중요한 것이 Authorization이다.

보면 Authorization 헤더에 KakaoAK (한 칸 띄고) (API 키) 임을 나타낸다.

HttpURLConnection con = (HttpURLConnection)url.openConnection();
con.setRequestProperty("Authorization", "KakaoAK " + kakao_apikey);
con.setRequestMethod("GET");

이런식으로 할 예정이다. 보면 KakaoAK 하고 한 칸 띄운 것을 볼 수 있다.

 

이제 파라미터인데 query만 필수이므로 query는 필수적으로 넣어주고, 여기서 나는 category_group_code, x, y, radius만 사용할 예정이다. (category_group_code에서 FD6값은 API 정보에 음식점이라는 정보라고 나와있음)

 

x와 y는 위도 경도이므로 서울 시청의 위도 경도를 알아야하는데 카카오 api에서 주소 검색하기라는 api를 통해 위도 경도를 알 수 있지만 일단은 구글 지도를 통해서 위도 경도를 알아낸 후 진행했다.(나중에 구현 예정)

 

서울 시청의 위도, 경도

위도 : 37.5606326

경도 : 126.9433486

 

코드를 봐보면

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;

@Service
public class KakaoAPI {

    @Value("${kakao_apikey}")
    private String kakao_apikey;

    public String getRestaurant() {
        try {
            // 맛집 단어 UTF-8로 인코딩
            String query = URLEncoder.encode("맛집", "UTF-8");

            // 파라미터를 사용하여 요청 URL을 구성한다.
            String apiURL = "https://dapi.kakao.com/v2/local/search/keyword.JSON?" +
                    "query=" + query
                    + "&category_group_code=" + "FD6"
                    + "&x=" + "37.5606326"
                    + "&y=" + "126.9433486"
                    + "&radius=" + "100";
            URL url = new URL(apiURL);
            HttpURLConnection con = (HttpURLConnection)url.openConnection();
            
            // 요청 헤더를 setRequestProperty로 지정해준다. 헤더가 더 많을시 더 추가하면 됨.
            con.setRequestProperty("Authorization", "KakaoAK " + kakao_apikey);
            con.setRequestMethod("GET");
            
            // 응답 코드 확인
            int responseCode = con.getResponseCode();
            BufferedReader br;
            
            // 정상 응답이 200이므로(http 상태코드)
            if(responseCode == 200) { // 정상 호출
                br = new BufferedReader(new InputStreamReader(con.getInputStream()));
            } else {  // 에러 발생
                br = new BufferedReader(new InputStreamReader(con.getErrorStream()));
            }
            String inputLine;
            StringBuffer response = new StringBuffer();
            while ((inputLine = br.readLine()) != null) {
                response.append(inputLine);
            }
            br.close();
//            System.out.println(response.toString());
            return response.toString();
        } catch (Exception e) {
            System.out.println(e);
        }
        return "";
    }
}

설명은 대충 주석에 적었고, service와 controller를 구현한다.

  • LocationService
package com.lunchpick.lunchpick.service;

import com.lunchpick.lunchpick.service.externalAPI.KakaoAPI;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;


@Service
@RequiredArgsConstructor
public class LocationService {

    private final KakaoAPI kakaoAPI;

    public String getRestaurant() {
        return kakaoAPI.getRestaurant();
    }


}
  • PickController
package com.lunchpick.lunchpick.controller;

import com.lunchpick.lunchpick.service.LocationService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
public class PickController {

    private final LocationService locationService;

    @RequestMapping(value = "/test", method = RequestMethod.GET)
    @ResponseBody
    public String getRest(){
        return locationService.getRestaurant();
    }
}

이렇게 하고 결과를 확인하면

제대로 결과가 나왔다.

 

🎁 중간에 발생했던 문제점들

  1. NullPointException이 떴었는데,
    private final KakaoAPI kakaoAPI;​
    여기서 final을 뺐었다. 즉, 의존성 주입이 안된 상태였던 것...

 

👑 해결할 점

  1. 현재는 응답을 String으로 받았지만 ResponseDTO를 통해 받아야 한다.
  2. 주소를 통해 위도, 경도를 얻을 수 있도록 해야 함.

 

728x90
반응형