지도 기반 서비스를 만들다 보면 주소를 좌표로 변환하거나, 두 지점 간의 거리를 계산해야 하는 상황이 자주 생긴다. 다만 대부분의 개발자들은 Google Maps Platform이 단순한 지도 표시 도구일 줄 알고, 실제로는 매우 강력한 Geocoding, Distance Matrix, Places 같은 API들이 있다는 걸 모르는 경우가 많다. 이번에는 Google Maps Platform API 키 발급부터 시작해서, 주소 지오코딩, 역 지오코딩, 거리 계산, 장소 검색까지 실제 프로젝트에서 쓸 수 있는 완벽한 구현 방법을 소개하겠다.

 

1단계. Google Cloud Console에서 API 키 발급받기

Google Maps Platform을 사용하려면 먼저 Google Cloud Console에서 프로젝트를 생성하고 API를 활성화해야 한다.

1) Google Cloud Console 접속
console.cloud.google.com에 접속해서 Google 계정으로 로그인한다. 프로젝트가 없다면 새 프로젝트를 생성하고, 기존 프로젝트가 있으면 선택한다.

2) Maps API 활성화
좌측 메뉴에서 '라이브러리'를 클릭한 후, "Maps" 검색창에 입력해서 다음 API들을 활성화한다.

  • Geocoding API (주소 ↔ 좌표 변환)
  • Distance Matrix API (두 지점 간 거리 계산)
  • Places API (장소 검색 및 상세 정보)
  • Maps JavaScript API (프론트엔드 지도 표시)

3) API 키 생성
'사용자 인증 정보' 메뉴에서 '사용자 인증 정보 만들기' → '서드파티 라이브러리'를 선택해 API 키를 생성한다. 생성된 키를 복사해 안전한 곳에 보관한다.

4) API 제한 설정 (필수)
생성된 API 키를 클릭해서 '애플리케이션 제한사항'에서 'HTTP 리퍼러(웹사이트)'를 선택하고, 본인의 도메인을 등록한다. 그리고 'API 제한사항'에서 위에서 활성화한 Maps API만 선택하도록 제한하면 보안이 훨씬 높아진다.

 

2단계. 주소를 좌표로 변환하기 - Geocoding API

가장 기본적인 기능이 Geocoding이다. "서울시 강남구 테헤란로 123"같은 주소를 위도/경도로 변환한다.

✗ 잘못된 코드 - 에러 처리 없이 API 응답 직접 사용
<?php
$address = '서울시 강남구 테헤란로 123';
$apiKey = 'YOUR_GOOGLE_MAPS_API_KEY';
$url = "https://maps.googleapis.com/maps/api/geocode/json?address=" . urlencode($address) . "&key=" . $apiKey;

$response = file_get_contents($url);
$data = json_decode($response, true);

// 에러 체크 없이 바로 접근하면 배열 구조를 모를 때 Undefined Index 발생
$lat = $data['results'][0]['geometry']['location']['lat'];
$lng = $data['results'][0]['geometry']['location']['lng'];

echo "위도: $lat, 경도: $lng";
?>

이 코드는 3가지 문제가 있다. 첫째, 네트워크 오류 처리가 없다. 둘째, Google의 응답 상태 코드를 확인하지 않는다. 셋째, 검색 결과가 없을 때 배열 접근 에러가 발생한다.

✓ 올바른 코드 - 완벽한 에러 처리와 응답 검증
<?php
function geocodeAddress($address, $apiKey) {
    $url = "https://maps.googleapis.com/maps/api/geocode/json";
    
    $params = [
        'address' => $address,
        'key' => $apiKey,
        'language' => 'ko'  // 한글 응답
    ];
    
    $url .= '?' . http_build_query($params);
    
    // cURL로 안전한 요청
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curlError = curl_error($ch);
    curl_close($ch);
    
    // 네트워크 오류 체크
    if ($curlError) {
        return [
            'success' => false,
            'error' => 'Network error: ' . $curlError
        ];
    }
    
    // HTTP 상태 코드 체크
    if ($httpCode !== 200) {
        return [
            'success' => false,
            'error' => 'HTTP Error: ' . $httpCode
        ];
    }
    
    $data = json_decode($response, true);
    
    // Google API 상태 확인
    if ($data['status'] !== 'OK') {
        return [
            'success' => false,
            'error' => 'Google API Error: ' . $data['status'],
            'message' => $data['error_message'] ?? 'Unknown error'
        ];
    }
    
    // 검색 결과 확인
    if (empty($data['results'])) {
        return [
            'success' => false,
            'error' => 'No results found for this address'
        ];
    }
    
    // 첫 번째 결과 반환
    $location = $data['results'][0];
    
    return [
        'success' => true,
        'latitude' => $location['geometry']['location']['lat'],
        'longitude' => $location['geometry']['location']['lng'],
        'formatted_address' => $location['formatted_address'],
        'place_id' => $location['place_id']
    ];
}

// 사용 예
$result = geocodeAddress('서울시 강남구 테헤란로 123', 'YOUR_API_KEY');

if ($result['success']) {
    echo "주소: " . $result['formatted_address'] . "\n";
    echo "위도: " . $result['latitude'] . "\n";
    echo "경도: " . $result['longitude'] . "\n";
} else {
    echo "오류: " . $result['error'] . "\n";
}
?>

결과:

주소: 테헤란로, 강남구, 서울, 대한민국
위도: 37.4979
경도: 127.0567

 

3단계. 좌표를 주소로 변환하기 - Reverse Geocoding

반대로 위도/경도로부터 주소를 얻는 것을 Reverse Geocoding이라 한다. GPS 데이터를 주소로 표시할 때 자주 쓰인다.

✓ Reverse Geocoding 구현
<?php
function reverseGeocodeCoordinates($latitude, $longitude, $apiKey) {
    $url = "https://maps.googleapis.com/maps/api/geocode/json";
    
    $params = [
        'latlng' => $latitude . ',' . $longitude,
        'key' => $apiKey,
        'language' => 'ko'
    ];
    
    $url .= '?' . http_build_query($params);
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($httpCode !== 200) {
        return ['success' => false, 'error' => 'HTTP Error'];
    }
    
    $data = json_decode($response, true);
    
    if ($data['status'] !== 'OK' || empty($data['results'])) {
        return ['success' => false, 'error' => 'No address found'];
    }
    
    $addresses = [];
    foreach ($data['results'] as $result) {
        $addresses[] = [
            'formatted_address' => $result['formatted_address'],
            'types' => $result['types']
        ];
    }
    
    return ['success' => true, 'addresses' => $addresses];
}

// 사용 예
$result = reverseGeocodeCoordinates(37.4979, 127.0567, 'YOUR_API_KEY');

if ($result['success']) {
    echo "주소: " . $result['addresses'][0]['formatted_address'] . "\n";
} else {
    echo "오류: " . $result['error'];
}
?>

 

4단계. 두 지점 간 거리 계산하기 - Distance Matrix API

택시 앱이나 배달 서비스처럼 두 장소 간의 거리와 예상 이동 시간을 구할 때 사용한다.

✓ Distance Matrix 구현
<?php
function calculateDistance($originLat, $originLng, $destLat, $destLng, $apiKey) {
    $url = "https://maps.googleapis.com/maps/api/distancematrix/json";
    
    $params = [
        'origins' => $originLat . ',' . $originLng,
        'destinations' => $destLat . ',' . $destLng,
        'key' => $apiKey,
        'mode' => 'driving',  // driving, walking, bicycling, transit
        'language' => 'ko'
    ];
    
    $url .= '?' . http_build_query($params);
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($httpCode !== 200) {
        return ['success' => false, 'error' => 'HTTP Error'];
    }
    
    $data = json_decode($response, true);
    
    if ($data['status'] !== 'OK') {
        return ['success' => false, 'error' => $data['status']];
    }
    
    if (empty($data['rows'][0]['elements'][0])) {
        return ['success' => false, 'error' => 'No route found'];
    }
    
    $element = $data['rows'][0]['elements'][0];
    
    // 경로가 없을 때 (예: 섬)
    if ($element['status'] !== 'OK') {
        return [
            'success' => false,
            'error' => 'Route not found: ' . $element['status']
        ];
    }
    
    return [
        'success' => true,
        'distance_meters' => $element['distance']['value'],
        'distance_text' => $element['distance']['text'],
        'duration_seconds' => $element['duration']['value'],
        'duration_text' => $element['duration']['text']
    ];
}

// 사용 예
$result = calculateDistance(37.4979, 127.0567, 37.5665, 126.9780, 'YOUR_API_KEY');

if ($result['success']) {
    echo "거리: " . $result['distance_text'] . "\n";
    echo "예상 시간: " . $result['duration_text'] . "\n";
} else {
    echo "오류: " . $result['error'];
}
?>

결과:

거리: 9.5 km
예상 시간: 21분

 

5단계. 주의사항과 흔한 실수

✗ 1번 실수: 요청 제한(Rate Limiting) 무시
Google Maps API는 무료 플랜에서 초당 요청 제한이 있다. 대량 데이터 처리할 때는 요청을 지연시켜야 한다.

<?php
// ✗ 잘못된 코드 - 1000개 주소를 즉시 변환
foreach ($addresses as $address) {
    $result = geocodeAddress($address, $apiKey);
    // 요청이 너무 빨라서 API 제한에 걸림
}

// ✓ 올바른 코드 - 요청 사이에 지연 추가
foreach ($addresses as $address) {
    $result = geocodeAddress($address, $apiKey);
    sleep(1);  // 1초 대기
}
?>

✗ 2번 실수: API 키를 코드에 하드코딩
API 키를 git에 커밋하면 누구나 사용할 수 있게 된다. 환경 변수나 설정 파일에 보관해야 한다.

<?php
// ✗ 잘못된 코드
$apiKey = 'AIzaSyDxxxxxxxxxxxxxxxx';

// ✓ 올바른 코드
$apiKey = getenv('GOOGLE_MAPS_API_KEY');
if (!$apiKey) {
    die('API key not configured');
}
?>

✗ 3번 실수: 한국 주소 입력 시 문제
Google Maps API는 기본적으로 영문 주소를 기준으로 한다. 한글 주소는 반드시 language 파라미터를 'ko'로 설정해야 한다.

<?php
// ✗ 한글 주소가 제대로 인식 안 될 수 있음
$params = [
    'address' => '서울시 강남구 테헤란로 123',
    'key' => $apiKey
];

// ✓ 한글 처리를 위해 language 추가
$params = [
    'address' => '서울시 강남구 테헤란로 123',
    'key' => $apiKey,
    'language' => 'ko'
];
?>

 

6단계. 응답 캐싱으로 비용 절감하기

같은 주소에 대해 반복적으로 API를 호출하면 비용이 낭비된다. Redis나 데이터베이스에 캐싱하면 훨씬 저렴하게 운영할 수 있다.

<?php
function geocodeAddressWithCache($address, $apiKey) {
    // 1단계: 캐시 확인 (Redis 예시)
    $cacheKey = 'geocode_' . md5($address);
    $cached = redis_get($cacheKey);
    
    if ($cached) {
        return json_decode($cached, true);
    }
    
    // 2단계: 캐시 미스 시 API 호출
    $result = geocodeAddress($address, $apiKey);
    
    // 3단계: 성공한 결과만 캐싱 (24시간)
    if ($result['success']) {
        redis_setex($cacheKey, 86400, json_encode($result));
    }
    
    return $result;
}

function redis_get($key) {
    // Redis 연결 코드
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $value = $redis->get($key);
    $redis->close();
    return $value;
}

function redis_setex($key, $ttl, $value) {
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $redis->setex($key, $ttl, $value);
    $redis->close();
}
?>

 

마무리

Google Maps Platform API는 주소 변환, 거리 계산, 장소 검색을 통해 위치 기반 서비스의 핵심을 담당한다. 올바른 에러 처리, 요청 제한 관리, 응답 캐싱이 모여서 안정적이고 저비용의 서비스를 만든다. 이 글의 코드를 참고해 자신의 프로젝트에 맞게 응용하면, 신뢰할 수 있는 지도 기능을 빠르게 구현할 수 있을 것이다.