Kakao developers API를 이용하여 주소로부터 좌표(위도, 경도) 추출해내기

728x90

서론


프로젝트 기능과 관련하여 클라이언트가 입력한 주소에서 위도 및 경도 좌표를 추출해야할 일이 생겼다. 주소에서 위도 및 경도를 꺼내기 위해서는 직접 주소에 위도 및 경도 정보를 매칭한 데이터를 소장하고 있거나, 배포된 API를 활용하여 주소 정보를 보내고 위도 및 경도 정보를 받는 방법이 있다. 개인 프로젝트에서는 API를 활용하여 주소에 대응하는 좌표값을 받는 것이 현실적인 방안일 것이다.

주소를 좌표로 변환하기 위한 API 종류

 


주소를 좌표로 변환하기 위해 활용할 수 있는 API는 아래와 같은 옵션이 존재한다.

1. 오픈 API - GeoCoder API 2.0
https://www.vworld.kr/dev/v4dv_geocoderguide2_s001.do
국토교통부에서 제공하는 공식 오픈API이며, 이용은 무료지만 하루 요청 건수가 4만 건으로 제한된다.

2. 주소기반산업지원서비스 API
행정안전부에서 제공하는 도로명주소 기반 API이다. 반환되는 entX 및 entY가 위도, 경도가 아니기 때문에 위도와 경도로 변환해주는 과정이 추가적으로 필요하다.

3. Kakao Developers - 로컬 API 
카카오에서 제공하는 API이며 무료다. 개발 문서가 상당히 보기 편하게 제공된다. 일일 제공량은 하루 10만 건으로 제한되어 GeoCoder API에 비해 널널한 편이다.

본 글쓴이는 개발 편의성과 일일 요청 건수를 고려하여 Kakao Developers에서 제공하는 로컬 API를 사용하여 주소를 좌표로 변환해볼 것이다. 본 글은 Kakao API를 사용하여 사용자의 주소 정보에서 좌표값을 추출하는 예제를 보여줄 것이다. 사용 언어는 JAVA고 Spring을 활용할 것이다.

Kakao developer에 가입하여 어플리케이션 추가하여 앱 키 받아오기

Kakao 계정 만들기

우선 Kakao developers API들을 사용하려면 Kakao 계정이 있어야 한다. Kakao 계정이 없다면 만들어주자. 계정이 있다면 kakao 계정으로 로그인하면 된다.

kakao developer에 어플리케이션 등록하기 


Kakao developers API에 유효한 요청을 보내기 위해서는 Kakao developers에서 발급한 앱 키가 있어야 한다. 앱 키를 발급받기 위해서는 Kakao Developer에 아래와 같이 내 어플리케이션을 등록해야한다.



앱 등록과 앱 키 발급에 관련된 사항은 다음 Kakao Developers에서 제공하는 공문서를 참고하여 진행하도록 하자.

https://developers.kakao.com/docs/latest/ko/getting-started/app

플랫폼 등록은 하지 않아도 API를 호출할 수 있다.

앱 등록이 정상적으로 완료되면 아래와 같이 API 호출에 필요한 키를 확인할 수 있다.



Kakao API를 이용하여 주소를 좌표로 변환하기 (Spring, JAVA)

프로젝트 환경

자바 버전: 19
스프링 버전: 3.0.6

dependency

implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.json:json:20230227'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

 

특정 좌표값을 가져오기 위해서 JSONObject 객체를 생성해야하므로 JSON 라이브러리가 반드시 필요하다. Entity의 Getter와 Setter 및 생성자 생성을 위해 lombok도 dependency에 등록해준다.

어플리케이션 코드


우선 전체 코드부터 살펴보겠다.

AddressService.class

주소를 좌표로 변환하는 여기서 클래스를 생성한다. 클래스 명은 AddressService로 한다. 전체코드는 아래와 같다.

 

@Service
public class AddressService {
    
    private final String uri = "https://dapi.kakao.com/v2/local/search/address.json";

    @Value("${kakao.local.key}")
    private String kakaoLocalKey;

    public Coordinates getCoordinate(){
        RestTemplate restTemplate = new RestTemplate();

        String apiKey = "KakaoAK " + kakaoLocalKey;
        String address = "서울시 강남구 테헤란로 131";
        
        // 요청 헤더에 만들기, Authorization 헤더 설정하기
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.set("Authorization", apiKey);
        HttpEntity<String> entity = new HttpEntity<>(httpHeaders);

        UriComponents uriComponents = UriComponentsBuilder
                .fromHttpUrl(uri)
                .queryParam("query",address)
                .build();

        ResponseEntity<String> response = restTemplate.exchange(uriComponents.toString(), HttpMethod.GET, entity, String.class);

        // API Response로부터 body 뽑아내기
        String body = response.getBody();
        JSONObject json = new JSONObject(body);
        // body에서 좌표 뽑아내기
        JSONArray documents = json.getJSONArray("documents");
        String x = documents.getJSONObject(0).getString("x");
        String y = documents.getJSONObject(0).getString("y");

        return new Coordinates(x, y);
    }
}



Coordinates.class

AddressService의 반환값을 받기 위해 아래 Entity가 필요하다.

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Coordinates {
    private String x;
    private String y;
}



코드 파헤치기


카카오 디벨로퍼 API에서 로컬 요청을 위해서는 아래와 같은 양식으로 HTTP 요청을 보내야 한다. 

 


해당 요청을 만들기 위해서 Spring에서는 아래와 같이 코드를 작성하는 것이다.

URI 생성

Kakao developers에 API를 요청하기 위한 URI는 정해져있다. 이것을 필드로 설정한다.

private final String uri = "https://dapi.kakao.com/v2/local/search/address.json";

 

 

앱 키 가져오기

API를 요청하기 위해서는 Kakao developer에서 발급한 앱키를 Authorization 헤더에 넣어서 HTTP 요청해야한다. 이 키를 .env에 저장해두고 application.properties를 통해 @Value 애노테이션을 사용하여 가져온다. (.env는 .gitignore에 등록되어 git 업로드 시 github에 업로드 되지 않아서 앱 키가 github에 노출되는 것을 방지한다.)

- AddressService 코드

@Value("${kakao.local.key}")
private String kakaoLocalKey;


- application.properties 코드

# Kakao setting
kakao.local.key=${KAKAO_LOCAL_KEY}

 

요청에 담아보낼 API key와 address 생성


가져온 앱 키에 "KakaoAK "를 앞부분에 붙여서 Authorization에 넣어 보내야 정상적으로 요청이 이뤄진다. 좌표로 변환할 address는 임의로 작성하였다. 실사용에서는 이를 대체하여 해당 메서드의 input 매개변수로 String address 값을 불러와 사용하면 된다.

String apiKey = "KakaoAK " + kakaoLocalKey;
String address = "서울시 강남구 테헤란로 131";

 

 

HTTP 요청에 보낼 헤더 설정하기


Spring에서 제공하는 HttpHeaders와 HttpEntity를 사용하면 HTTP 요청에 보낼 헤더를 손쉽게 설정할 수 있다.

 

HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("Authorization", apiKey);
HttpEntity<String> entity = new HttpEntity<>(httpHeaders);

 

HTTP 요청에 포함할 쿼리 작성하기


Spring의 UriComponents를 사용하여 쿼리를 보낼 수 있다. fromHttpUrl에 필드에 생성한 uri 변수를 사용한다.

 

UriComponents uriComponents = UriComponentsBuilder
            .fromHttpUrl(uri)
            .queryParam("query",address)
            .build();

 

RestTemplate

API  요청을 보내기 위해 Spring에서 제공하는 RestTemplate을 사용한다.

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(uriComponents.toString(), HttpMethod.GET, entity, String.class);



restTemplate로 API 요청하여 응답을 받는 메서드는 3가지가 존재한다. 
 1. postForEntity()
 2. exchange()
 3. execute()

이들 메서드의 차이는 아래 웹사이트에 잘 작성되어있으니 참고하기 바란다.

https://www.baeldung.com/spring-resttemplate-exchange-postforentity-execute

여기선 exchage() 함수를 사용하여 API 요청할 것이다. restTemplate의 exchange 함수에는 다음과 같은 매개변수가 필요하다.

1. uri를 String 형태로
2. Http 메서드
3. HttpEntity
4. 반환받을 변수 형식

위 코드는 필요 매개변수를 순서대로 넣어준 것이다. Entity는 기존에 선언하여 Authorization에 api key가 있는 entity를 넣어줘야 한다.

API 응답으로부터 좌표 뽑아내기

restTemplate의 exchage() 메서드의 반환 값의 형식은 가변적이다. 여기서는 응답을 String.class로 지정하여 문자열로 받았는데, 그 이유는 JSONObject를 사용하여 특정 키를 통해 좌표값을 뽑내기 위해서다.

String body = response.getBody();
JSONObject json = new JSONObject(body);

JSONArray documents = json.getJSONArray("documents");
String x = documents.getJSONObject(0).getString("x");
String y = documents.getJSONObject(0).getString("y");



JSONObject는 getJSONArray(), getJSONObject() 그리고 getString()을 통해 JSON 값을 가져올 수 있다.

getJSONArray()는 JSON 데이터에서 배열로 지정된 데이터를 뽑아낼 수 있고, getJSONObject()는 JSON 데이터에서 하위 JSON으로 선언된 데이터를 뽑아낼 수 있으며, getString()은 특정 키에 해당하는 값을 추출해낼 수 있다. 세 메서드가 취급하는 데이터 양식이 상이하므로 서로 혼동하여 사용하지 않도록 주의한다.

POSTMAN으로 API 동작 테스트 하기


POSTMAN을 통해 해당 AddressService의 로직이 제대로 동작하는지 테스트 할 것이다. 우선 테스트를 위해 아래와 같이 간략하게 컨트롤러를 작성한다.

@RestController
public class AddressController {

    private final AddressService addressService;

    public AddressController(AddressService addressService) {
        this.addressService = addressService;
    }

    @GetMapping("/address")
    public Coordinates address(){
        return addressService.getCoordinate();
    }
}



POSTMAN을 구동하여 해당 매핑 주소로 GET 요청을 보낸다. 현재 Service 로직에서 헤더 및 쿼리(임의의 주소)를 모두 알아서 설정하므로 POSTMAN은 그저 해당 주소로 GET 요청을 보내기만 하면 된다.




API 응답 결과로 좌표값이 반환되는 것을 확인할 수 있다.