Bermigrasi dari Geocoding v3 ke v4

Developer Wilayah Ekonomi Eropa (EEA)

Geocoding API v4 memperkenalkan beberapa metode baru yang menggantikan fungsi di API v3. Panduan ini menunjukkan cara memigrasikan aplikasi Anda untuk menggunakan metode v4 baru.

Anda dapat menggunakan kunci API yang ada dengan metode v4 baru. Namun, jika Anda telah meminta peningkatan kuota pada API v3, Anda harus meminta peningkatan pada API v4 baru.

Bermigrasi dari Geocoding Forward v3

Jika Anda menggunakan Geocoding v3 untuk melakukan geocoding pada alamat, Anda harus bermigrasi ke metode Geocode an address v4, yang menerima permintaan GET.

API v4 mengubah nama, struktur, dan dukungan untuk beberapa parameter. Sebaiknya Anda menggunakan mask kolom untuk menentukan kolom yang ingin ditampilkan dalam respons.

Meminta perubahan parameter

Parameter v3 Parameter v4 Catatan
address, components address Alamat tidak terstruktur (v3 address) kini diteruskan di jalur URL. Komponen alamat terstruktur (components v3) dapat diteruskan sebagai parameter kueri address.*. Lihat Mereproduksi filter komponen v3.
bounds locationBias.rectangle Diganti namanya; struktur diubah menjadi objek.
language languageCode Nama telah diganti. Jika dihilangkan, v3 akan menggunakan header Accept-Language atau ditetapkan secara default ke en, sedangkan v4 ditetapkan secara default ke bahasa dan skrip lokal lokasi.
region regionCode Nama telah diganti. Jika dihilangkan, v3 akan ditetapkan secara default ke us, sedangkan v4 tidak memiliki nilai default.
extra_computations Dihapus Diganti dengan metode SearchDestinations.

Perubahan kolom respons

Kolom v3 Kolom v4 Catatan
status, error_message Dihapus v4 menggunakan kode status HTTP dan isi error.
results.address_components.long_name / results.address_components.short_name results.addressComponents.longText / results.addressComponents.shortText Nama telah diganti.
results.geometry.location_type results.granularity Nama telah diganti.
results.geometry.location results.location Nama kolom: lat/lng -> latitude/longitude.
results.geometry.viewport results.viewport Nama kolom: northeast/southwest -> high/low.
results.postcode_localities results.postalCodeLocalities Nama telah diganti. Kini ditampilkan untuk satu atau beberapa lokalitas (v3 memerlukan >1).
results.partial_match Dihapus
Baru results.addressComponents.languageCode Bahasa komponen alamat tertentu.
Baru results.bounds Batas eksplisit menggunakan high/low.
Baru results.place Nama resource untuk tempat.
Baru results.postalAddress Objek PostalAddress terstruktur.

Mereproduksi filter komponen v3

Geocoding Forward di Geocoding v3 menyertakan parameter components yang memungkinkan pemfilteran ketat hasil untuk komponen tertentu (misalnya, components=country:US). Geocoding Forward di v4 tidak mendukung jenis pemfilteran ketat ini dalam parameter permintaan. Di v4, Anda dapat memberikan informasi alamat sebagai satu string tidak terstruktur di jalur atau sebagai parameter kueri terstruktur seperti address.addressLines, address.locality, address.administrativeArea, address.postalCode, dan address.regionCode. Parameter terstruktur tidak berfungsi sebagai filter ketat. Sebagai gantinya, semua komponen yang disediakan digabungkan untuk membentuk alamat lengkap yang akan dicoba di-geocoding oleh API. API akan menelusuri kecocokan terbaik untuk seluruh alamat yang ditentukan di semua komponen. Menyediakan komponen secara terstruktur dapat membantu API memahami intent dengan lebih baik, terutama saat informasi alamat dikumpulkan dari kolom formulir yang terpisah. Hal ini dapat membantu API dalam menangani kesalahan ketik kecil atau ambiguitas dalam setiap komponen, karena jenis informasi di setiap kolom sudah jelas.

Untuk mencapai perilaku yang mirip dengan filter komponen ketat v3, Anda harus menerapkan pemfilteran sisi klien pada array results yang ditampilkan oleh API v4 berdasarkan objek postalAddress dan addressComponents dalam respons.

Tabel berikut menunjukkan kecocokan terbaik antara filter components v3 dan kolom postalAddress v4:

filter komponen v3 Kolom respons v4
country postalAddress.regionCode
postal_code postalAddress.postalCode
administrative_area postalAddress.administrativeArea atau addressComponents

Contoh pemfilteran sisi klien

Contoh berikut menunjukkan cara memfilter hasil untuk mencapai perilaku yang mirip dengan pemfilteran komponen v3 untuk kolom yang didukung: negara, wilayah administratif, dan kode pos. Sebaiknya jangan memfilter kolom lain karena tidak ada kriteria pemfilteran yang andal.

Filter menurut Negara

Cocokkan address.regionCode dari permintaan Anda dengan postalAddress.regionCode di setiap hasil. Perhatikan bahwa meskipun API menerima kode wilayah huruf kecil dalam permintaan, API selalu menampilkan kode wilayah dalam huruf besar dalam respons, sehingga Anda harus menormalisasi input ke huruf besar sebelum melakukan perbandingan.

Contoh Kode Python
def filter_by_country(results, region_code):
    return [
        res for res in results
        if res.get('postalAddress', {}).get('regionCode') == region_code.upper()
    ]

# Example usage:
# v4_response = ... # API call response
# filtered = filter_by_country(v4_response.get('results', []), 'US')
Contoh Kode Node.js
function filterByCountry(results, regionCode) {
    return results.filter(res => res.postalAddress?.regionCode === regionCode.toUpperCase());
}

// Example usage:
// const v4Response = ... # API call response
// const filtered = filterByCountry(v4Response.results, 'US');
Filter menurut Wilayah Administratif

Cocokkan address.administrativeArea dari permintaan Anda dengan postalAddress.administrativeArea di setiap hasil. Sama seperti kode negara, Anda harus menormalisasi input menjadi huruf besar sebelum melakukan perbandingan. Hal ini hanya dapat diandalkan jika administrativeArea dalam permintaan Anda diberikan dengan singkatan 2 huruf standar. postalAddress.administrativeArea dalam respons mungkin tidak cocok secara langsung dengan akhiran kode ISO 3166-2 karena beberapa alasan. Pertama, di beberapa area, subdivisi yang sesuai dengan kode ISO 3166-2 bukan bagian dari representasi standar alamat pos. Misalnya, di Spanyol, wilayah administratif level 1 (misalnya, "CN" untuk Canarias) mungkin ada di addressComponents, tetapi postalAddress.administrativeArea mungkin berisi area level 2 (misalnya, "Santa Cruz de Tenerife"). Kedua, di beberapa area, singkatan subdivisi tidak umum digunakan dan diwakili di postalAddress.administrativeArea dengan nama yang lebih panjang (untuk alasan serupa, addressComponents.shortText untuk komponen alamat yang sesuai dengan subdivisi mungkin tidak cocok dengan akhiran kode ISO 3166-2 subdivisi). Selain itu, subdivisi dalam beberapa kasus dapat direpresentasikan di komponen alamat untuk administrative_area_level_n dengan n lebih besar dari 1. Untuk mendapatkan hasil yang paling komprehensif, Anda harus memeriksa kecocokan di postalAddress.administrativeArea dan addressComponents apa pun dengan jenis administrative_area_level_n (misalnya, administrative_area_level_1).

Contoh Kode Python
def filter_by_admin_area(results, admin_area):
    target = admin_area.upper()
    filtered = []
    for res in results:
        # Check postalAddress
        pa_aa = res.get('postalAddress', {}).get('administrativeArea', '')
        if pa_aa == target:
            filtered.append(res)
            continue
        # Check all administrative area levels in addressComponents
        for comp in res.get('addressComponents', []):
            is_admin_level = any(t.startswith('administrative_area_level_')
                               for t in comp.get('types', []))
            if is_admin_level:
                short = comp.get('shortText', '')
                if short == target:
                    filtered.append(res)
                    break
    return filtered

# Example usage:
# filtered = filter_by_admin_area(v4_response.get('results', []), 'CA')
Contoh Kode Node.js
function filterByAdminArea(results, adminArea) {
    const target = adminArea.toUpperCase();
    return results.filter(res => {
        // Check postalAddress.administrativeArea
        if (res.postalAddress?.administrativeArea === target) {
            return true;
        }
        // Check addressComponents for any administrative area level
        return res.addressComponents?.some(c => {
            const isAdmin = c.types?.some(t => t.startsWith('administrative_area_level_'));
            return isAdmin && c.shortText === target;
        });
    });
}

// Example usage:
// const filtered = filterByAdminArea(v4Response.results, 'CA');
Filter menurut Kode Pos

Cocokkan address.postalCode dari permintaan Anda dengan postalAddress.postalCode di setiap hasil. Anda harus menormalisasi kode pos input dan hasil sebelum perbandingan. Logika normalisasi sangat bergantung pada wilayah. Pendekatan dasar melibatkan penghapusan spasi dan tanda hubung serta konversi ke huruf yang konsisten.

Normalisasi yang lebih lanjut mungkin diperlukan untuk menangani awalan kode pos (misalnya, "L2" di Inggris Raya) atau akhiran (misalnya, "+4" di kode pos AS). Logika normalisasi spesifik yang diperlukan akan bervariasi bergantung pada negara dan format kode pos yang terlibat. Anda mungkin perlu menyesuaikan fungsi normalisasi yang disediakan atau menerapkan logika yang lebih canggih untuk wilayah yang Anda targetkan.

Contoh yang diberikan menangani kode pos AS dan memungkinkan pencocokan pada basis 5 digit meskipun ZIP+4 diberikan atau ditampilkan.

Contoh Kode Python (berfokus pada Kode Pos AS)
import re

def normalize_postal_code_us(pc):
    # Basic normalization for US: uppercase, alphanumeric only
    if not pc:
        return ""
    normalized = re.sub(r'[^A-Z0-9]', '', pc.upper())
    # Return only the first 5 digits for US ZIP codes
    return normalized[:5]

def filter_by_postal_code_us(results, postal_code):
    normalized_input = normalize_postal_code_us(postal_code)
    if not normalized_input:
        return []
    filtered_results = []
    for res in results:
        pa_pc = res.get('postalAddress', {}).get('postalCode', '')
        if normalize_postal_code_us(pa_pc) == normalized_input:
            filtered_results.append(res)
    return filtered_results

# Example usage:
# Matches '94043', '94043-1351', '940431351'
# filtered = filter_by_postal_code_us(v4_response.get('results', []), '94043')
# filtered = filter_by_postal_code_us(v4_response.get('results', []), '94043-1234')
Contoh Kode Node.js (berfokus pada Kode Pos AS)
function normalizePostalCodeUs(pc) {
    // Basic normalization for US: uppercase, alphanumeric only
    const normalized = (pc || '').toUpperCase().replace(/[^A-Z0-9]/g, '');
    // Return only the first 5 digits for US ZIP codes
    return normalized.substring(0, 5);
}

function filterByPostalCodeUs(results, postalCode) {
    const normalizedInput = normalizePostalCodeUs(postalCode);
    if (!normalizedInput) {
        return [];
    }
    return results.filter(res => {
        const paPc = res.postalAddress?.postalCode || '';
        return normalizePostalCodeUs(paPc) === normalizedInput;
    });
}

// Example usage:
// Matches '94043', '94043-1351', '940431351'
// const filtered = filterByPostalCodeUs(v4Response.results, '94043');
// const filtered = filterByPostalCodeUs(v4Response.results, '94043-1234');

Bermigrasi dari Geocoding Terbalik v3

Jika Anda menggunakan Geocoding Terbalik v3 untuk mengubah koordinat menjadi alamat, Anda harus bermigrasi ke metode Geocoding terbalik lokasi v4, yang menerima permintaan GET.

API v4 mengubah nama, struktur, dan dukungan untuk beberapa parameter. Sebaiknya Anda menggunakan mask kolom untuk menentukan kolom yang ingin ditampilkan dalam respons.

Meminta perubahan parameter

Parameter v3 Parameter v4 Catatan
language languageCode Nama telah diganti. Jika dihilangkan, v3 akan menggunakan header Accept-Language atau ditetapkan secara default ke en, sedangkan v4 ditetapkan secara default ke bahasa dan skrip lokal lokasi.
region regionCode Nama telah diganti. Jika dihilangkan, v3 akan ditetapkan secara default ke us, sedangkan v4 tidak memiliki nilai default.
result_type types Diganti namanya; menggunakan parameter kueri berulang.
location_type granularity Diganti namanya; menggunakan parameter kueri berulang.
extra_computations Dihapus Diganti dengan metode SearchDestinations.

Perubahan kolom respons

Kolom v3 Kolom v4 Catatan
status, error_message Dihapus v4 menggunakan kode status HTTP dan isi error.
results.address_components.long_name / results.address_components.short_name results.addressComponents.longText / results.addressComponents.shortText Nama telah diganti.
results.geometry.location_type results.granularity Nama telah diganti.
results.geometry.location results.location Nama kolom: lat/lng -> latitude/longitude.
results.geometry.viewport results.viewport Nama kolom: northeast/southwest -> high/low.
Baru results.addressComponents.languageCode Bahasa komponen alamat tertentu.
Baru results.bounds Batas eksplisit menggunakan high/low.
Baru results.place Nama resource untuk tempat.
Baru results.postalAddress Objek PostalAddress terstruktur.

Bermigrasi dari Deskripsi alamat v3

Di Geocoding API v3, meneruskan extra_computations=ADDRESS_DESCRIPTORS akan menampilkan objek address_descriptor yang berisi landmarks[] dan areas[]. Di Geocoding API v4, kemampuan ini digantikan oleh metode SearchDestinations (POST /v4/geocode/destinations), yang menampilkan konteks spasial lengkap langsung dalam setiap objek Destination.

Tabel berikut memetakan kolom address_descriptor v3 lama ke kolom SearchDestinations v4 yang setara:

Kolom address_descriptor v3 Kolom SearchDestinations v4 Catatan Migrasi
landmarks[] destinations[].landmarks[] Minta destinations.landmarks di X-Goog-FieldMask Anda.
landmarks[].place_id landmarks[].place.placeId Digabungkan di dalam objek place (PlaceView).
landmarks[].display_name landmarks[].place.displayName Teks yang dilokalkan (text dan languageCode).
landmarks[].types landmarks[].place.types Array string jenis tempat.
landmarks[].spatial_relationship landmarks[].relationalDescription Alih-alih enum mentah (ACROSS_THE_ROAD, AROUND_THE_CORNER), v4 menampilkan frasa yang dilokalkan dan dapat dibaca manusia (misalnya, "Across from Central Park").
landmarks[].straight_line_distance_meters landmarks[].straightLineDistanceMeters Diganti namanya menjadi lower camelCase.
landmarks[].travel_distance_meters landmarks[].travelDistanceMeters Diganti namanya menjadi camelCase huruf kecil.
areas[] (enum containment) destinations[].containingPlaces[] & subDestinations[] Setara terdekat yang tersedia untuk hierarki struktural: kompleks, kampus, mal, dan bangunan yang mencakup ditampilkan sebagai objek PlaceView terstruktur di containingPlaces[] dan subDestinations[] (dengan structureType ditetapkan ke GROUNDS atau BUILDING dan garis batas displayPolygon opsional). Perhatikan bahwa tidak ada pengganti langsung 1:1 untuk area kedekatan lingkungan/distrik atau enum containment v3 (NEAR, WITHIN, OUTSKIRTS).

Bermigrasi dari geocoding Tempat v3

Jika Anda menggunakan place_id untuk mendapatkan alamat untuk ID Tempat tertentu dengan Geocoding v3, Anda harus bermigrasi ke metode Place Geocoding v4, yang menerima permintaan GET.

API v4 mengubah nama, struktur, dan dukungan untuk beberapa parameter. Sebaiknya Anda menggunakan mask kolom untuk menentukan kolom yang ingin ditampilkan dalam respons.

Meminta perubahan parameter

Parameter v3 Parameter v4 Catatan
place_id Kolom place dalam proto permintaan ID Tempat kini disediakan sebagai parameter jalur places/{place}, misalnya: https://geocode.googleapis.com/v4/geocode/places/ChIJj61dQgK6j4AR4GeTYWZsKWw. Ini dipetakan ke kolom tempat dalam permintaan yang mendasarinya.
language languageCode Nama telah diganti. Jika dihilangkan, v3 akan menggunakan header Accept-Language atau ditetapkan secara default ke en, sedangkan v4 ditetapkan secara default ke bahasa dan skrip lokal lokasi.
region regionCode Nama telah diganti. Jika dihilangkan, v3 akan ditetapkan secara default ke us, sedangkan v4 tidak memiliki nilai default.

Perubahan kolom respons

Kolom v3 Kolom v4 Catatan
status, error_message Dihapus v4 menggunakan kode status HTTP dan isi error.
results (root) v4 menampilkan satu objek hasil, bukan array results.
results.address_components.long_name / results.address_components.short_name addressComponents.longText / addressComponents.shortText Nama telah diganti.
results.geometry.location_type granularity Nama telah diganti.
results.geometry.location location Nama kolom: lat/lng -> latitude/longitude.
results.geometry.viewport viewport Nama kolom: northeast/southwest -> high/low.
results.postcode_localities postalCodeLocalities Nama telah diganti. Kini ditampilkan untuk satu atau beberapa lokalitas (v3 memerlukan >1).
Baru addressComponents.languageCode Bahasa komponen alamat tertentu.
Baru bounds Batas eksplisit menggunakan high/low.
Baru place Nama resource untuk tempat.
Baru postalAddress Objek PostalAddress terstruktur.

Bermigrasi dari Geocoding Hyperlocal Data ke Destinations

Fitur berikut di Geocoding API v3 digantikan oleh metode SearchDestinations Geocoding API v4:

  • Masuk
  • Titik navigasi
  • Garis batas bangunan
  • Area

Jika Anda menggunakan Geocoding API v3 untuk fitur di atas, gunakan dokumen ini untuk membantu Anda menggunakan metode SearchDestinations sebagai gantinya untuk mendapatkan fitur ini. Dokumen ini menjelaskan tempat menemukan fitur ini dalam respons SearchDestinations, serta perbedaan cara fitur ini direpresentasikan dalam respons API antara Geocoding API v3 dan metode SearchDestinations Geocoding API v4.

Masuk

Untuk mendapatkan pintu masuk yang terkait dengan destination, gunakan kolom destination.entrances.

Setiap entrance di destination.entrances memiliki kolom berikut (menggantikan skema buildings.entrances v3 lama):

  • displayName - kolom opsional baru yang berisi nama yang dapat dibaca manusia untuk pintu masuk, misalnya "Gate B".
  • location - lokasi jenis LatLng menggunakan latitude dan longitude (menggantikan lat/lng v3).
  • tags - sama dengan kolom tags dari pintu masuk Geocoding API v3 (seperti PREFERRED).
  • place - nama resource tempat (misalnya, places/ChIJ...), menggantikan kolom building_place_id dari Geocoding API v3. Di v4, tempat ini dapat merepresentasikan struktur tujuan apa pun (bangunan, kampus, atau taman), bukan hanya bangunan.

Untuk mendapatkan titik navigasi yang terkait dengan destination, gunakan kolom destination.navigationPoints.

Setiap navigationPoint di destination.navigationPoints memiliki kolom berikut (menggantikan skema navigation_points v3 lama):

  • navigationPointToken - string token terenkripsi yang digunakan untuk merutekan ke titik navigasi spesifik ini dalam metode ComputeRoutes Routes API (Waypoint.navigationPointToken). Lihat Merutekan menggunakan token titik navigasi.
  • displayName - kolom opsional baru yang berisi nama yang dapat dibaca manusia untuk titik navigasi, misalnya "5th Ave".
  • location - lokasi jenis LatLng menggunakan latitude dan longitude.
  • travelModes - mirip dengan kolom restricted_travel_modes dari Geocoding API v3, kecuali bahwa v4 menentukan mode perjalanan yang dapat diterima (DRIVE, WALK), bukan mode perjalanan yang dibatasi.
  • usage - kolom baru yang menentukan kasus penggunaan kedatangan yang didukung untuk titik navigasi (seperti PICKUP, DROPOFF, atau PARKING).

Garis batas bangunan

Untuk mendapatkan garis batas bangunan yang terkait dengan destination, gunakan kolom displayPolygon dari objek placeView di destination yang merepresentasikan bangunan (menggantikan array buildings.building_outlines v3 lama). Untuk setiap placeView, periksa apakah itu adalah bangunan dengan kolom placeView.structureType. Jika jenis strukturnya adalah BUILDING, Anda bisa mendapatkan kerangka dari kolom placeView.displayPolygon. placeView juga akan memiliki kolom tambahan untuk bangunan yang tidak ada di Geocoding API v3.

destination dapat memiliki objek placeView yang mewakili bangunan di kolom berikut:

  • destination.primary - tempat utama untuk tujuan.
  • destination.containingPlaces - kolom berulang yang menyimpan tempat yang lebih besar yang "berisi" tempat utama. Misalnya, jika tempat utama adalah subpremise, containingPlaces biasanya menyimpan placeView yang mewakili bangunan.
  • destination.subDestinations - kolom berulang yang menyimpan sub-tujuan dari tempat utama (misalnya, unit apartemen atau suite individual dalam sebuah bangunan).

Perhatikan bahwa format placeView.displayPolygon cocok dengan format garis batas bangunan di Geocoding API v3, yang merupakan format GeoJSON, menggunakan format RFC 7946.

Area

Serupa dengan garis batas bangunan, untuk mendapatkan halaman yang terkait dengan destination, gunakan kolom displayPolygon dari objek placeView di destination yang mewakili halaman (menggantikan array grounds v3 lama). Untuk setiap placeView, periksa apakah poligon tersebut adalah poligon tanah dengan kolom placeView.structureType. Jika jenis strukturnya adalah GROUNDS, Anda bisa mendapatkan struktur dari kolom placeView.displayPolygon. placeView juga akan memiliki kolom tambahan untuk dasar yang tidak ada di Geocoding API v3.

destination dapat memiliki objek placeView yang mewakili halaman di kolom berikut:

  • destination.primary
  • destination.containingPlaces
  • destination.subDestinations

Perhatikan bahwa format placeView.displayPolygon cocok dengan format batas lahan di Geocoding API v3, yang merupakan format GeoJSON, menggunakan format RFC 7946.

Presisi hasil

Di Geocoding API v3, kolom location_type dalam geometri respons menunjukkan presisi hasil, dan beberapa klien akan memberi peringkat atau memfilter hasil berdasarkan nilai ini (ROOFTOP, RANGE_INTERPOLATED, GEOMETRIC_CENTER, dan APPROXIMATE). Dalam migrasi Geocoding API v4 standar, kolom ini diganti namanya menjadi granularity.

Di Destinations API (SearchDestinations v4), tidak ada kolom location_type. Sebagai gantinya, informasi spasial ditangani secara berbeda:

  • Tidak memerlukan pemfilteran sisi klien manual: Meskipun Geocoding standar memberikan beberapa hasil di berbagai tingkat perincian, metode SearchDestinations meminimalkan ambiguitas dengan me-resolve ke satu tujuan yang dioptimalkan jika memungkinkan. Hal ini menghilangkan kebutuhan klien untuk memfilter menurut jenis lokasi guna menentukan hasil terbaik.
  • Informasi spasial yang diwakili oleh jenis struktur dan poligon tampilan: Geometri dan struktur spasial ditunjukkan oleh:
    • displayPolygon (untuk geometri yang tepat).
    • Kolom structureType dalam objek placeView.
  • Pemetaan jenis struktur:
    • structureType dari POINT, BUILDING, atau SECTION umumnya sesuai dengan yang sebelumnya disebut ROOFTOP.
    • structureType dari GROUNDS umumnya sesuai dengan GEOMETRIC_CENTER.

Menggunakan mask kolom untuk meminta fitur ini

Metode SearchDestinations memerlukan mask kolom, seperti yang dijelaskan dalam Memilih kolom yang akan ditampilkan. Masker kolom dapat ditetapkan ke * untuk menampilkan semua kolom, atau Anda dapat menetapkannya ke kolom tertentu yang ingin Anda terima. Misalnya, permintaan API berikut menetapkan mask kolom untuk menerima semua kolom yang diperlukan guna mendapatkan pintu masuk, titik navigasi, garis batas bangunan, dan halaman tujuan:

curl -X POST -d '{"place": "places/ChIJG3kh4hq6j4AR_XuFQnV0_t8"}' \
  -H "X-Goog-Api-Key: API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-Goog-FieldMask: destinations.entrances,destinations.navigationPoints,destinations.primary,destinations.containingPlaces,destinations.subDestinations" \
  https://geocode.googleapis.com/v4/geocode/destinations

Resep Migrasi & Pola Kode Umum

Saat memigrasikan alur kerja yang kompleks dari Geocoding v3 atau Geocoding++ ke SearchDestinations, gunakan resep kode berikut untuk mengekstrak struktur spasial dan alamat umum.

Mengekstrak poligon bangunan terbaik

Jika Anda ingin merender batas gedung untuk lokasi atau tujuan:

  1. Periksa apakah tempat primary memiliki structureType === 'BUILDING' dan berisi displayPolygon.
  2. Jika tidak, periksa containingPlaces untuk menemukan bangunan yang mengelilinginya (berguna jika tujuan utama adalah subtujuan dari bangunan yang lebih besar).
  3. Jika tidak ada bangunan yang mencakup, periksa subDestinations untuk melihat apakah bangunan individual tercantum.
Contoh Kode Python
def get_best_building_polygon(destination):
    primary = destination.get('primary', {})
    if primary.get('structureType') == 'BUILDING' and 'displayPolygon' in primary:
        return primary['displayPolygon']

    # Check containing places for the parent building
    for place in destination.get('containingPlaces', []):
        if place.get('structureType') == 'BUILDING' and 'displayPolygon' in place:
            return place['displayPolygon']

    # Fallback to sub-destinations if available
    for place in destination.get('subDestinations', []):
        if place.get('structureType') == 'BUILDING' and 'displayPolygon' in place:
            return place['displayPolygon']

    return None
Contoh Kode Node.js
function getBestBuildingPolygon(destination) {
    const { primary = {}, containingPlaces = [], subDestinations = [] } = destination;

    if (primary.structureType === 'BUILDING' && primary.displayPolygon) {
        return primary.displayPolygon;
    }

    const parentBuilding = containingPlaces.find(
        p => p.structureType === 'BUILDING' && p.displayPolygon
    );
    if (parentBuilding) {
        return parentBuilding.displayPolygon;
    }

    const subBuilding = subDestinations.find(
        p => p.structureType === 'BUILDING' && p.displayPolygon
    );
    return subBuilding?.displayPolygon || null;
}

Mengekstrak garis batas tanah

Jika Anda memerlukan batas kompleks apartemen, kampus perusahaan, pusat perbelanjaan, atau taman:

  1. Jika tempat primary mewakili seluruh kompleks (structureType === 'GROUNDS'), gunakan primary.displayPolygon.
  2. Jika tempat primary adalah bangunan atau pintu masuk yang terletak di dalam kompleks yang lebih besar, temukan area yang mengelilinginya di containingPlaces.
Contoh Kode Python
def get_grounds_polygon(destination):
    primary = destination.get('primary', {})
    if primary.get('structureType') == 'GROUNDS' and 'displayPolygon' in primary:
        return primary['displayPolygon']

    for place in destination.get('containingPlaces', []):
        if place.get('structureType') == 'GROUNDS' and 'displayPolygon' in place:
            return place['displayPolygon']

    return None
Contoh Kode Node.js
function getGroundsPolygon(destination) {
    const { primary = {}, containingPlaces = [] } = destination;

    if (primary.structureType === 'GROUNDS' && primary.displayPolygon) {
        return primary.displayPolygon;
    }

    const groundsPlace = containingPlaces.find(
        p => p.structureType === 'GROUNDS' && p.displayPolygon
    );
    return groundsPlace?.displayPolygon || null;
}

Memilih tempat terkenal untuk tampilan alamat versus kedatangan jarak dekat

Geocoding v3 address_descriptor menampilkan enum spatial_relationship (WITHIN, BESIDE, BEHIND, NEAR, ACROSS_THE_ROAD, AROUND_THE_CORNER). Di SearchDestinations:

  • Tidak ada enum hubungan mentah. Sebagai gantinya, gunakan relationalDescription.text secara langsung. File ini berisi frasa yang dilokalkan dan siap ditampilkan seperti "Across from Central Park" atau "Behind the convention center". Jangan tambahkan "Near " secara manual.
  • Gunakan tags untuk memilih tempat terkenal yang tepat untuk kasus penggunaan Anda:
    • ARRIVAL: Tempat terkenal hiperlokal yang terletak tepat di samping, menghadap, atau di seberang jalan dari tujuan (biasanya dalam jarak 50–100 meter). Paling cocok untuk kedatangan pengemudi secara real-time, konfirmasi pengiriman kurir, atau kartu kedatangan dalam aplikasi.
    • ADDRESS: Tempat terkenal di sekitar (biasanya dalam jarak 100–500 meter). Paling cocok untuk checkout yang ditampilkan kepada pelanggan, peninjauan pesanan, atau disambiguasi tujuan sebelum perjalanan.
    • Jika tempat terkenal memiliki tag ADDRESS dan ARRIVAL, tempat tersebut terkenal di lingkungan sekitar dan berada tepat di samping tujuan.
Contoh Kode Python
def get_best_relational_landmark(destination, is_last_mile=True):
    """Select the best landmark based on user context.

    Args:
        destination: Destination object from SearchDestinations.
        is_last_mile: True for arrival and delivery guidance (prefers ARRIVAL tags).
                      False for address display and disambiguation (prefers ADDRESS tags).

    Returns:
        Dict with landmark description, distances, tags, and placeId, or None.
    """
    landmarks = destination.get('landmarks', [])
    if not landmarks:
        return None

    target_tag = 'ARRIVAL' if is_last_mile else 'ADDRESS'

    # Landmarks are ranked by relevance and proximity. Select the first candidate matching the target tag.
    for lm in landmarks:
        tags = lm.get('tags', [])
        if target_tag in tags or ('ARRIVAL' in tags and 'ADDRESS' in tags):
            description = lm.get('relationalDescription', {}).get('text')
            if description:
                return {
                    'description': description,
                    'travelDistanceMeters': lm.get('travelDistanceMeters'),
                    'straightLineDistanceMeters': lm.get('straightLineDistanceMeters'),
                    'tags': tags,
                    'placeId': lm.get('place', {}).get('placeId')
                }

    # Fallback to the first available landmark with a relational description if no tagged match is found
    for lm in landmarks:
        description = lm.get('relationalDescription', {}).get('text')
        if description:
            return {
                'description': description,
                'travelDistanceMeters': lm.get('travelDistanceMeters'),
                'straightLineDistanceMeters': lm.get('straightLineDistanceMeters'),
                'tags': lm.get('tags', []),
                'placeId': lm.get('place', {}).get('placeId')
            }

    return None
Contoh Kode Node.js
/**
 * Select the best landmark based on user context.
 *
 * @param {Object} destination Destination object from SearchDestinations.
 * @param {boolean} [isLastMile=true] True for arrival and delivery guidance
 *        (prefers ARRIVAL tags). False for address display and disambiguation
 *        (prefers ADDRESS tags).
 * @return {Object|null}
 */
function getBestRelationalLandmark(destination, isLastMile = true) {
    const landmarks = destination.landmarks || [];
    if (!landmarks.length) return null;

    const targetTag = isLastMile ? 'ARRIVAL' : 'ADDRESS';

    // Landmarks are ranked by relevance and proximity. Select the first candidate matching the target tag.
    const match = landmarks.find((lm) => {
        const tags = lm.tags || [];
        return (tags.includes(targetTag) || (tags.includes('ARRIVAL') && tags.includes('ADDRESS'))) &&
               lm.relationalDescription?.text;
    }) || landmarks.find((lm) => lm.relationalDescription?.text);

    if (match) {
        return {
            description: match.relationalDescription.text,
            travelDistanceMeters: match.travelDistanceMeters,
            straightLineDistanceMeters: match.straightLineDistanceMeters,
            tags: match.tags || [],
            placeId: match.place?.placeId || null,
        };
    }

    return null;
}

Menentukan rute ke titik navigasi kendaraan dan pintu masuk pilihan

Alur kerja pengiriman dan kedatangan jarak jauh menggabungkan dua jenis titik akses spasial yang saling melengkapi:

  • Mengemudi belokan demi belokan: Mengarahkan kendaraan ke titik penurunan di jalan yang ditentukan menggunakan navigationPoints. Titik navigasi diberi peringkat terlebih dahulu berdasarkan kedekatan dan relevansi, sehingga kandidat pertama dengan mode perjalanan yang Anda inginkan (seperti 'DRIVE') dan tag penggunaan (seperti 'DROPOFF' atau 'PICKUP') memberikan titik jalan kendaraan yang optimal. Kirim navigationPointToken-nya ke metode ComputeRoutes Routes API (Waypoint.navigationPointToken) atau Navigation SDK. Jika tidak ada titik mengemudi yang disesuaikan dengan jalan, gunakan pintu masuk bangunan atau centroid utama.
  • Akses pintu fisik: Pandu kurir yang berjalan kaki atau penumpang ke pintu masuk gedung menggunakan destinations.entrances. Periksa tags untuk 'PREFERRED' guna menemukan pintu masuk yang kemungkinan menyediakan akses fisik langsung. Jika tidak ada data pintu masuk, gunakan titik navigasi pejalan kaki (travelModes termasuk 'WALK') atau centroid utama.
Contoh Kode Python
def get_routing_and_arrival_points(destination, usage_tag=None):
    navigation_points = destination.get('navigationPoints', [])
    entrances = destination.get('entrances', [])
    primary_location = destination.get('primary', {}).get('location')

    # 1. Doorstep / Physical Entrance
    # Prefer PREFERRED entrance -> any entrance -> WALK nav point -> primary location
    preferred_entrance = None
    for ent in entrances:
        if 'PREFERRED' in ent.get('tags', []):
            preferred_entrance = ent
            break
    if not preferred_entrance and entrances:
        preferred_entrance = entrances[0]

    walk_nav_point = None
    for np in navigation_points:
        if 'WALK' in np.get('travelModes', []):
            walk_nav_point = np
            break

    if preferred_entrance:
        doorstep_location = preferred_entrance.get('location')
    elif walk_nav_point:
        doorstep_location = walk_nav_point.get('location')
    else:
        doorstep_location = primary_location

    # 2. Vehicle Routing Waypoint
    # Find a driving navigation point. If usage_tag (such as 'DROPOFF' or 'PICKUP')
    # is specified, prioritize a candidate with that usage tag; otherwise fall back
    # to the first available driving point.
    drive_nav_point = None
    fallback_drive_point = None
    for np in navigation_points:
        if 'DRIVE' in np.get('travelModes', []):
            if usage_tag and usage_tag in np.get('usages', []):
                drive_nav_point = np
                break  # Exact match for desired usage tag
            elif fallback_drive_point is None:
                fallback_drive_point = np  # First driving point as fallback

    if not drive_nav_point:
        drive_nav_point = fallback_drive_point

    if drive_nav_point:
        vehicle_location = drive_nav_point.get('location')
        nav_token = drive_nav_point.get('navigationPointToken')
    elif preferred_entrance:
        vehicle_location = preferred_entrance.get('location')
        nav_token = None
    else:
        vehicle_location = primary_location
        nav_token = None

    return {
        'vehicleRoutingWaypoint': {
            'navigationPointToken': nav_token,
            'location': vehicle_location,
        },
        'doorstepLocation': doorstep_location,
    }
Contoh Kode Node.js
function getRoutingAndArrivalPoints(destination, usageTag = null) {
    const navigationPoints = destination.navigationPoints || [];
    const entrances = destination.entrances || [];
    const primaryLocation = destination.primary?.location || null;

    // 1. Doorstep / Physical Entrance
    const preferredEntrance = entrances.find(ent => ent.tags?.includes('PREFERRED'))
        || entrances[0]
        || null;

    const walkNavPoint = navigationPoints.find(np => np.travelModes?.includes('WALK'))
        || null;

    const doorstepLocation = preferredEntrance?.location
        || walkNavPoint?.location
        || primaryLocation;

    // 2. Vehicle Routing Waypoint
    // Find a driving navigation point. If usageTag (such as 'DROPOFF' or 'PICKUP')
    // is specified, prioritize a candidate with that usage tag; otherwise fall back
    // to the first available driving point.
    const driveNavPoint = (usageTag && navigationPoints.find(np => np.travelModes?.includes('DRIVE') && np.usages?.includes(usageTag)))
        || navigationPoints.find(np => np.travelModes?.includes('DRIVE'))
        || null;

    let vehicleLocation = primaryLocation;
    let navToken = null;
    if (driveNavPoint) {
        vehicleLocation = driveNavPoint.location;
        navToken = driveNavPoint.navigationPointToken;
    } else if (preferredEntrance) {
        vehicleLocation = preferredEntrance.location;
    }

    return {
        vehicleRoutingWaypoint: {
            navigationPointToken: navToken,
            location: vehicleLocation,
        },
        doorstepLocation: doorstepLocation,
    };
}

Pertimbangan keamanan

Geocoding API v4 dirancang sebagai API server ke server. Tidak ada jalur migrasi langsung untuk pengguna JavaScript dari v3 ke v4. Memanggil metode v4 langsung dari JavaScript sisi klien (misalnya, di browser) menggunakan kunci API akan membuat kunci API Anda berisiko tinggi dicuri dan disalahgunakan.

Pembatasan perujuk HTTP, meskipun berguna, bukanlah perlindungan yang memadai untuk endpoint layanan web karena dapat dengan mudah diabaikan oleh penyerang yang memalsukan header Referer dalam permintaan mereka.

Cara yang direkomendasikan untuk menggunakan Geocoding API v4 adalah dari server backend Anda sendiri. Aplikasi klien Anda harus membuat permintaan ke server perantara ini, yang kemudian memanggil Google API dengan aman menggunakan kunci API yang dilindungi (misalnya, kunci yang disimpan dalam variabel lingkungan atau secret manager). Hal ini memastikan bahwa kunci API Anda tidak pernah terekspos dalam kode frontend.

Alternatif untuk kebutuhan sisi klien

Jika Anda memiliki kebutuhan sisi klien yang memerlukan geocoding, pertimbangkan untuk menggunakan salah satu solusi sisi klien yang ada:

  • Layanan Geocoding di Maps JavaScript API: Layanan Geocoding terus menggunakan backend v3 dan dirancang untuk digunakan di lingkungan browser.
  • Kit UI Places: Gunakan Kit UI Places, termasuk elemen Place Autocomplete, untuk elemen antarmuka pengguna yang terkait dengan alamat.