본문 바로가기
BackEnd/Project

[PharmNav] Ch05. kakao 주소검색 api 구현

by 개발 Blog 2024. 9. 2.

공부 내용을 정리하고 앞으로의 학습에 이해를 돕기 위해 작성합니다.

이번 장에서는 Kakao 주소 검색 API를 활용해 특정 위치에 대한 정보를 검색하는 방법을 다뤄보고 코드를 구현해 본다.

 

api 스펙 살펴보기

Kakao 주소 검색 API에 대한 자세한 정보는 다음 링크에서 확인할 수 있다.

https://developers.kakao.com/docs/latest/ko/local/dev-guide

 

외부 API 사용 시 사전 검토 사항

외부 API를 사용하기 전에 아래 사항을 반드시 검토해야 한다:

  • API 호출 제한: API의 호출 제한 사항을 확인해야 한다. 해당 내용은 https://developers.kakao.com/terms/latest/ko/site-policies#quota에서 확인할 수 있다.
  • REST API 테스트 도구 사용: 실제 개발에 들어가기 전에 curl 또는 Postman과 같은 도구를 사용해 API를 호출해 보고, 원하는 결과가 나오는지 테스트해야 한다.

Kakao Developers에서 애플리케이션 추가

  • https://developers.kakao.com/에 로그인 후, 새로운 애플리케이션을 추가한다.
  • 애플리케이션 생성 후, 앱 키를 확인한다. 이 중 REST API 키를 API 호출에 사용하게 된다. 이 키는 외부에 노출되지 않도록 주의해야 한다.

 

Postman을 활용한 API 호출

API 호출을 위해 Postman을 설치하고 실행한다. 공식 가이드를 참고해 아래와 같이 설정을 한다.

 

응답 메시지 확인

요청을 보내면, 원하는 주소에 대한 정보를 담은 JSON 응답 메시지를 받을 수 있다. 이 응답 메시지에서 특히 중요한 것은 해당 위치의 위도(x)와 경도(y) 정보이다. 이 정보를 프로젝트에서 사용할 수 있다.

위의 절차를 따르면 Kakao API를 통해 특정 주소의 정보를 쉽게 검색할 수 있다. 프로젝트의 요구 사항에 맞춰 이 정보를 활용하면 된다.

 

api 스펙 구현하기

이번에는 Spring Boot 프로젝트에서 Kakao 주소 검색 API를 활용해 특정 위치에 대한 정보를 가져오는 방법을 다룬다. 이 과정에서 API 키를 환경변수로 설정하고, API 응답에서 필요한 정보만 추출해 사용할 수 있도록 DTO(Data Transfer Object)를 작성하는 방법도 살펴본다.

 

1. Kakao REST API 키 설정

실무에서는 API 호출 리밋에 걸리지 않도록 로컬과 운영 환경에서 다른 API 키를 사용하는 것이 일반적이다. 하지만 지금은 호출 횟수가 많지 않으니, 공통으로 사용하도록 한다. API 키는 Application.yaml 파일에 환경변수로 설정하고, Spring Boot에서 사용할 수 있도록 세팅한다.

spring:
  profiles:
    active: local # default
    group:
      local:
        - local
        - common
      prod:
        - prod
        - common

---
spring:
  config:
    activate:
      on-profile: common
      
//추가
kakao:
  rest:
    api:
      key: ${KAKAO_REST_API_KEY}

---
spring:
  config:
    activate:
      on-profile: local
  datasource:
    driver-class-name: org.mariadb.jdbc.Driver
    url: jdbc:mariadb://localhost:3306/pharmacy-recommendation
    username: ${SPRING_DATASOURCE_USERNAME}
    password: ${SPRING_DATASOURCE_PASSWORD}
  data:
    redis:
      host: localhost
      port: 6379
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: true
---
spring:
  config:
    activate:
      on-profile: prod

 

2. DTO 작성

DTO(Data Transfer Object)는 주로 데이터를 전달하기 위한 객체로, 서버와 클라이언트 간의 통신에서 데이터의 전송을 위해 사용된다. 

Kakao API의 응답 정보 중에서 필요한 위도(latitude), 경도(longitude) 정보만을 추출하기 위해 DTO를 작성한다. 

 

1) DocumentDto 클래스

이 클래스는 Kakao API 응답에서 특정 주소에 대한 정보를 담고 있는 객체이다.

package com.example.phamnav.api.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class DocumentDto {

    @JsonProperty("address_name")
    private String addressName;

    @JsonProperty("y")
    private double latitude;

    @JsonProperty("x")
    private double longitude;
}
  • @JsonProperty("address_name"): API 응답에서 address_name이라는 필드명을 가진 값을 Java 객체의 addressName 필드에 매핑한다. 이 애너테이션을 사용하면 JSON 응답의 필드명과 Java 객체의 필드명이 다를 때도, JSON 필드를 정확히 Java 필드에 매핑할 수 있다.
  • addressName: 요청된 주소의 이름을 나타내는 문자열이다.
  • latitude (y): 위도를 나타내는 값으로, Kakao API의 응답에서는 y라는 필드에 해당한다. 이 필드를 사용하여 지도상에서의 위도를 나타낼 수 있다.
  • longitude (x): 경도를 나타내는 값으로, Kakao API의 응답에서는 x라는 필드에 해당한다. 이 필드를 사용하여 지도상에서의 경도를 나타낼 수 있다.

2) KakaoApiResponseDto 클래스

이 클래스는 Kakao API에서의 전체 응답을 매핑하기 위한 DTO이다. 응답은 메타데이터와 문서 리스트로 구성되어 있다.

package com.example.phamnav.api.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class KakaoApiResponseDto {

    @JsonProperty("meta")
    private MetaDto metaDto;

    @JsonProperty("documents")
    private List<DocumentDto> documentList;
}
  • metaDto: 응답의 메타데이터를 담고 있는 객체로, 총결과의 개수나 페이지 정보 등을 포함한다. MetaDto 객체로 매핑된다.
  • documentList: 실제 주소 정보들이 포함된 리스트로, DocumentDto 객체들의 리스트로 매핑된다. 응답에서 여러 개의 주소 정보가 있을 수 있기 때문에 리스트 형태로 정의한다.

이 클래스는 API 호출의 응답 전체를 캡슐화하여, 나중에 필요한 데이터를 쉽게 접근할 수 있도록 해준다.

 

3) MetaDto 클래스

이 클래스는 응답의 메타데이터를 매핑하기 위한 DTO이다.

package com.example.phamnav.api.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class MetaDto {

    @JsonProperty("total_count")
    private Integer totalCount;

}
  • @JsonProperty("total_count"): JSON 응답에서 total_count라는 필드명을 가진 값을 Java 객체의 totalCount 필드에 매핑한다.
  • totalCount: 해당 요청에 대해 반환된 총 결과 수를 나타낸다. 예를 들어, 검색된 주소의 총개수를 의미한다.

이 클래스는 API 응답의 메타데이터를 추출하여 필요에 따라 사용할 수 있도록 한다.

 

3. RestTemplate 설정

RestTemplate은 Spring Framework에서 RESTful 웹 서비스를 호출하기 위해 제공하는 클래스이다. 이 클래스는 서버와의 통신을 간편하게 해주는 역할을 한다. HTTP 요청을 보내고, 응답을 받아올 수 있으며, JSON, XML 등의 데이터를 자동으로 객체로 변환해 준다.

 

RestTemplateConfig 클래스

RestTemplate 객체를 Spring Bean으로 등록하기 위해, 설정 클래스를 작성한다. 이 설정 클래스를 통해 애플리케이션에서 RestTemplate 객체를 주입받아 사용할 수 있다.

package com.example.phamnav.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
  • @Configuration: 이 클래스가 Spring 설정 클래스를 의미함을 나타낸다.
  • @Bean: 이 애너테이션을 통해 Spring 컨테이너에 RestTemplate 객체를 Bean으로 등록한다. 이후 다른 클래스에서 @Autowired 혹은 @RequiredArgsConstructor를 통해 이 객체를 주입받아 사용할 수 있다.

이렇게 설정하면 RestTemplate을 프로젝트 전반에서 자유롭게 사용할 수 있게 된다.

 

4. Kakao 주소 검색 서비스 구현

Kakao API를 호출하여 주소 검색을 수행하기 위해, KakaoAddressSearchService 클래스를 작성한다. 이 클래스는 앞서 설정한 RestTemplate을 사용하여 Kakao API와 통신을 담당한다.

package com.example.phamnav.api.service;

import com.example.phamnav.api.dto.KakaoApiResponseDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import java.net.URI;

@Slf4j
@Service
@RequiredArgsConstructor
public class KakaoAddressSearchService {

    private final RestTemplate restTemplate;
    private final KakaoUriBuilderService kakaoUriBuilderService;

    @Value("${kakao.rest.api.key}")
    private String kakaoRestApiKey;

    public KakaoApiResponseDto requestAddressSearch(String address) {

        if(ObjectUtils.isEmpty(address)) return null;

        URI uri = kakaoUriBuilderService.buildUriByAddressSearch(address);

        HttpHeaders headers = new HttpHeaders();
        headers.set(HttpHeaders.AUTHORIZATION, "KakaoAK " + kakaoRestApiKey);
        HttpEntity httpEntity = new HttpEntity(headers);

        // kakao api 호출
        return restTemplate.exchange(uri, HttpMethod.GET, httpEntity, KakaoApiResponseDto.class).getBody();
    }
}
  • @Service: 이 클래스가 서비스 레이어의 컴포넌트임을 나타낸다. Spring 컨테이너에서 자동으로 관리되며, 다른 클래스에서 주입받아 사용할 수 있다.
  • @Slf4j: Lombok에서 제공하는 애너테이션으로, 로그 기록을 위한 Logger 객체를 자동으로 생성한다. 로그를 통해 디버깅 정보를 남길 수 있다.
  • @RequiredArgsConstructor: Lombok 애너테이션으로, final 키워드가 붙은 필드에 대해 생성자를 자동으로 생성해 준다. 이를 통해 의존성 주입이 가능해진다.
  • @Value("${kakao.rest.api.key}"): application.yaml에 설정된 환경변수에서 Kakao API 키 값을 주입받아 사용한다.

이 클래스의 주요 기능은 Kakao API를 호출하여 주소 검색을 수행하는 것이다.

requestAddressSearch 메서드는 다음과 같이 작동한다.

  1. 주소 유효성 검사: 입력된 주소가 null 또는 빈 값인지 검사하고, 유효하지 않은 경우 null을 반환한다.
  2. URI 생성: 주소 검색을 위한 URI를 생성한다. URI 생성은 별도의 서비스인 KakaoUriBuilderService에서 수행된다.
  3. HTTP 헤더 설정: Kakao API 키를 포함한 HTTP 헤더를 생성한다. 이때 Authorization 헤더에 KakaoAK {API_KEY} 형식으로 API 키를 설정한다.
  4. API 호출: RestTemplate의 exchange 메서드를 사용해 GET 요청을 보낸다. 이때, 응답 데이터는 KakaoApiResponseDto 객체로 매핑된다.
  5. 결과 반환: API 호출의 결과로 받은 데이터를 반환한다.

5. Kakao API URI 생성 서비스

Kakao API 호출 시, 적절한 URI를 생성하기 위해 KakaoUriBuilderService 클래스를 작성한다. 이 클래스는 URI를 동적으로 생성해 주는 역할을 한다.

package com.example.phamnav.api.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;

@Slf4j
@Service
public class KakaoUriBuilderService {
    private static final String KAKAO_LOCAL_SEARCH_ADDRESS_URL = "https://dapi.kakao.com/v2/local/search/address.json";

    public URI buildUriByAddressSearch(String address) {
        UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(KAKAO_LOCAL_SEARCH_ADDRESS_URL);

        uriBuilder.queryParam("query", address);

        URI uri = uriBuilder.build().encode().toUri();
        log.info("[KakaoUriBuilderService buildUriByAddressSearch] address: {}, uri : {}", address, uri);

        return uri;

    }
}
  • @Service: 이 클래스가 Spring의 서비스 레이어 컴포넌트임을 나타낸다.
  • @Slf4j: 로그 기록을 위한 Logger 객체를 자동으로 생성해주는 Lombok 애너테이션.
  • UriComponentsBuilder: URI를 동적으로 생성하는 데 사용되는 Spring 클래스이다.

이 클래스의 주요 기능은 API 호출 시 사용할 URI를 동적으로 생성하는 것이다.

buildUriByAddressSearch 메서드는 다음과 같이 작동한다.

  1. 기본 URL 설정: Kakao API 주소 검색을 위한 기본 URL을 설정한다 (KAKAO_LOCAL_SEARCH_ADDRESS_URL).
  2. 쿼리 파라미터 추가: 검색할 주소를 쿼리 파라미터로 추가한다 (query=주소).
  3. URI 빌드 및 인코딩: 설정된 URL과 파라미터를 기반으로 URI를 생성하고, 이 URI를 반환한다.
  4. 로그 기록: 생성된 URI와 함께 입력된 주소를 로그로 기록하여 디버깅에 활용할 수 있다.

이렇게 생성된 URI는 KakaoAddressSearchService에서 API 호출 시 사용된다.

 

이번 장에서는 Spring Boot를 사용해 Kakao 주소 검색 API를 구현하는 방법을 다뤘다. RestTemplate 설정, DTO 작성, 그리고 서비스 구현을 통해 외부 API와의 통신을 효과적으로 처리할 수 있었다. 이러한 구조를 통해 유연하고 확장 가능한 API 연동 기능을 프로젝트에 적용할 수 있게 되었다.