Eseguire la migrazione da Geocoding v3 a v4

Sviluppatori dello Spazio economico europeo (SEE)

La versione 4 dell'API Geocoding introduce diversi nuovi metodi che sostituiscono le funzionalità della versione 3 dell'API. Questa guida mostra come eseguire la migrazione della tua app per utilizzare i nuovi metodi v4.

Puoi utilizzare le tue chiavi API esistenti con i nuovi metodi v4. Tuttavia, se hai richiesto un aumento della quota per la versione 3 dell'API, devi richiedere un aumento per le nuove API v4.

Esegui la migrazione dal geocoding diretto v3

Se utilizzi la geocodifica v3 per geocodificare gli indirizzi, devi eseguire la migrazione al metodo Geocodifica un indirizzo v4, che accetta una richiesta GET.

L'API v4 modifica i nomi, la struttura e il supporto di diversi parametri. Ti consigliamo vivamente di utilizzare una maschera di campo per specificare i campi che vuoi che vengano restituiti nella risposta.

Modifiche ai parametri di richiesta

Parametro v3 Parametro v4 Note
address, components address L'indirizzo non strutturato (v3 address) viene ora trasmesso nel percorso dell'URL. I componenti dell'indirizzo strutturato (v3 components) possono essere passati come parametri di query address.*. Consulta la sezione Riproduci i filtri dei componenti v3.
bounds locationBias.rectangle Rinominato; struttura modificata in oggetto.
language languageCode Rinominato. Se omesso, la versione v3 utilizza l'intestazione Accept-Language o il valore predefinito en, mentre la versione v4 utilizza per impostazione predefinita la lingua e lo script locali della località.
region regionCode Rinominato. Se omesso, v3 assume il valore predefinito us, mentre v4 non ha un valore predefinito.
extra_computations Rimosso Sostituito dal metodo SearchDestinations.

Modifiche ai campi di risposta

Campo v3 Campo v4 Note
status, error_message Rimosso La versione 4 utilizza i codici di stato HTTP e i corpi degli errori.
results.address_components.long_name/results.address_components.short_name results.addressComponents.longText/results.addressComponents.shortText Rinominato.
results.geometry.location_type results.granularity Rinominato.
results.geometry.location results.location Nomi dei campi: lat/lng -> latitude/longitude.
results.geometry.viewport results.viewport Nomi dei campi: northeast/southwest -> high/low.
results.postcode_localities results.postalCodeLocalities Rinominato. Ora restituito per una o più località (v3 richiede >1).
results.partial_match Rimosso
Novità results.addressComponents.languageCode Lingua del componente dell'indirizzo specifico.
Novità results.bounds Limiti espliciti utilizzando high/low.
Novità results.place Il nome della risorsa per il luogo.
Novità results.postalAddress Oggetto PostalAddress strutturato.

Riproduci i filtri dei componenti v3

Il geocoding diretto in Geocoding v3 includeva un parametro components che consentiva il filtro rigido dei risultati per componenti specifici (ad es. components=country:US). Il geocoding diretto in v4 non supporta questo tipo di filtro rigido nei parametri della richiesta. Nella versione 4, puoi fornire le informazioni sull'indirizzo come una singola stringa non strutturata nel percorso o come parametri di query strutturati come address.addressLines, address.locality, address.administrativeArea, address.postalCode e address.regionCode. I parametri strutturati non fungono da filtri rigidi. Invece, tutti i componenti forniti vengono combinati per formare l'indirizzo completo che l'API tenterà di geocodificare. L'API cerca la corrispondenza migliore per l'intero indirizzo specificato in tutti i componenti. Fornire i componenti in modo strutturato può aiutare l'API a comprendere meglio l'intent, soprattutto quando le informazioni sull'indirizzo vengono raccolte da campi del modulo separati. In questo modo, l'API può gestire piccoli errori di battitura o ambiguità all'interno di ogni componente, poiché il tipo di informazioni in ogni campo è chiaro.

Per ottenere un comportamento simile ai filtri dei componenti rigidi della versione 3, devi implementare il filtro lato client nell'array results restituito dall'API v4 in base agli oggetti postalAddress e addressComponents nella risposta.

La tabella seguente mostra la corrispondenza migliore tra i filtri components v3 e i campi postalAddress v4:

Filtro dei componenti v3 Campo di risposta v4
country postalAddress.regionCode
postal_code postalAddress.postalCode
administrative_area postalAddress.administrativeArea o addressComponents

Esempi di filtri lato client

Gli esempi seguenti mostrano come filtrare i risultati per ottenere un comportamento simile al filtro dei componenti della versione 3 per i campi supportati: paese, area amministrativa e codice postale. Non è consigliabile applicare filtri ad altri campi, poiché non esistono criteri di filtro affidabili.

Filtra per paese

Abbina il address.regionCode della tua richiesta con il postalAddress.regionCode in ogni risultato. Tieni presente che, sebbene l'API accetti codici regione in minuscolo nella richiesta, li restituisce sempre in maiuscolo nella risposta, pertanto devi normalizzare l'input in maiuscolo prima del confronto.

Esempio di codice 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')
Esempio di codice 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');
Filtra per area amministrativa

Abbina il address.administrativeArea della tua richiesta con il postalAddress.administrativeArea in ogni risultato. Analogamente ai codici paese, devi normalizzare l'input in lettere maiuscole prima del confronto. Questo è affidabile solo quando il valore administrativeArea nella richiesta viene fornito con un'abbreviazione standard di 2 lettere. Il valore postalAddress.administrativeArea nella risposta potrebbe non corrispondere direttamente ai suffissi del codice ISO 3166-2 per diversi motivi. In primo luogo, in alcune aree la suddivisione corrispondente al codice ISO 3166-2 non fa parte della rappresentazione standard degli indirizzi postali. Ad esempio, in Spagna, l'area amministrativa di livello 1 (ad es. "CN" per Canarias) potrebbe essere presente in addressComponents, ma postalAddress.administrativeArea potrebbe contenere l'area di livello 2 (ad es. "Santa Cruz de Tenerife"). In secondo luogo, in alcune aree l'abbreviazione della suddivisione non è di uso comune ed è rappresentata in postalAddress.administrativeArea con un nome più lungo (per motivi simili, addressComponents.shortText per il componente dell'indirizzo corrispondente alla suddivisione potrebbe non corrispondere al suffisso del codice ISO 3166-2 della suddivisione). Inoltre, in alcuni casi la suddivisione può essere rappresentata nel componente dell'indirizzo per administrative_area_level_n con n maggiore di 1. Per ottenere i risultati più completi, devi verificare la presenza di una corrispondenza sia in postalAddress.administrativeArea sia in qualsiasi addressComponents con un tipo administrative_area_level_n (ad es. administrative_area_level_1).

Esempio di codice 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')
Esempio di codice 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');
Filtra per codice postale

Abbina il address.postalCode della tua richiesta con il postalAddress.postalCode in ogni risultato. Devi normalizzare sia i codici postali di input che quelli dei risultati prima del confronto. La logica di normalizzazione dipende molto dalla regione. Un approccio di base prevede la rimozione di spazi e trattini e la conversione in un formato coerente.

Potrebbe essere necessaria una normalizzazione più avanzata per gestire i prefissi dei codici postali (ad es. "L2" nel Regno Unito) o i suffissi (ad es. "+4" nei codici postali degli Stati Uniti). La logica di normalizzazione specifica richiesta varia in base al paese e ai formati dei codici postali interessati. Potresti dover adattare le funzioni di normalizzazione fornite o implementare una logica più sofisticata per le regioni che stai scegliendo come target.

L'esempio fornito gestisce i codici postali degli Stati Uniti e consente la corrispondenza sulla base di 5 cifre anche se viene fornito o restituito il codice postale+4.

Esempio di codice Python (incentrato sul codice postale degli Stati Uniti)
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')
Esempio di codice Node.js (incentrato sul codice postale degli Stati Uniti)
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');

Esegui la migrazione dalla geocodifica inversa v3

Se utilizzi la geocodifica inversa v3 per convertire le coordinate in indirizzi, devi eseguire la migrazione al metodo Geocodifica inversa di una località v4, che accetta una richiesta GET.

L'API v4 modifica i nomi, la struttura e il supporto di diversi parametri. Ti consigliamo vivamente di utilizzare una maschera di campo per specificare i campi che vuoi che vengano restituiti nella risposta.

Modifiche ai parametri di richiesta

Parametro v3 Parametro v4 Note
language languageCode Rinominato. Se omesso, la versione v3 utilizza l'intestazione Accept-Language o il valore predefinito en, mentre la versione v4 utilizza per impostazione predefinita la lingua e lo script locali della località.
region regionCode Rinominato. Se omesso, v3 assume il valore predefinito us, mentre v4 non ha un valore predefinito.
result_type types Rinominato; utilizza parametri di query ripetuti.
location_type granularity Rinominato; utilizza parametri di query ripetuti.
extra_computations Rimosso Sostituito dal metodo SearchDestinations.

Modifiche ai campi di risposta

Campo v3 Campo v4 Note
status, error_message Rimosso La versione 4 utilizza i codici di stato HTTP e i corpi degli errori.
results.address_components.long_name/results.address_components.short_name results.addressComponents.longText/results.addressComponents.shortText Rinominato.
results.geometry.location_type results.granularity Rinominato.
results.geometry.location results.location Nomi dei campi: lat/lng -> latitude/longitude.
results.geometry.viewport results.viewport Nomi dei campi: northeast/southwest -> high/low.
Novità results.addressComponents.languageCode Lingua del componente dell'indirizzo specifico.
Novità results.bounds Limiti espliciti utilizzando high/low.
Novità results.place Il nome della risorsa per il luogo.
Novità results.postalAddress Oggetto PostalAddress strutturato.

Esegui la migrazione dai descrittori degli indirizzi v3

Nella versione 3 dell'API Geocoding, il passaggio di extra_computations=ADDRESS_DESCRIPTORS restituiva un oggetto address_descriptor contenente landmarks[] e areas[]. Nell'API Geocoding v4, questa funzionalità è sostituita dal metodo SearchDestinations (POST /v4/geocode/destinations), che restituisce un contesto spaziale completo direttamente all'interno di ogni oggetto Destination.

La seguente tabella mappa i campi v3 address_descriptor legacy ai relativi equivalenti v4 SearchDestinations:

Campo v3 address_descriptor Campo v4 SearchDestinations Note sulla migrazione
landmarks[] destinations[].landmarks[] Richiedi destinations.landmarks nel tuo X-Goog-FieldMask.
landmarks[].place_id landmarks[].place.placeId Inserito all'interno dell'oggetto place (PlaceView).
landmarks[].display_name landmarks[].place.displayName Testo localizzato (text e languageCode).
landmarks[].types landmarks[].place.types Array di stringhe di tipi di luoghi.
landmarks[].spatial_relationship landmarks[].relationalDescription Anziché un enum non elaborato (ACROSS_THE_ROAD, AROUND_THE_CORNER), la versione 4 restituisce una frase localizzata e leggibile (ad es. "Across from Central Park").
landmarks[].straight_line_distance_meters landmarks[].straightLineDistanceMeters Rinominato in lower camelCase.
landmarks[].travel_distance_meters landmarks[].travelDistanceMeters Rinominato in lower camelCase.
areas[] (enum containment) destinations[].containingPlaces[] e subDestinations[] Equivalente più vicino disponibile per la gerarchia strutturale: i complessi, i campus, i centri commerciali e gli edifici circostanti vengono restituiti come oggetti PlaceView strutturati in containingPlaces[] e subDestinations[] (con structureType impostato su GROUNDS o BUILDING e contorni displayPolygon facoltativi). Tieni presente che non esiste una sostituzione diretta 1:1 per le aree di prossimità di quartiere/distretto o per l'enum containment della versione 3 (NEAR, WITHIN, OUTSKIRTS).

Esegui la migrazione dalla geocodifica dei luoghi v3

Se utilizzi place_id per ottenere l'indirizzo di un ID luogo specifico con Geocoding v3, devi eseguire la migrazione al metodo Geocoding dei luoghi v4, che accetta una richiesta GET.

L'API v4 modifica i nomi, la struttura e il supporto di diversi parametri. Ti consigliamo vivamente di utilizzare una maschera di campo per specificare i campi che vuoi che vengano restituiti nella risposta.

Modifiche ai parametri di richiesta

Parametro v3 Parametro v4 Note
place_id Campo place nel proto della richiesta L'ID luogo viene ora fornito come parametro di percorso places/{place}, ad esempio: https://geocode.googleapis.com/v4/geocode/places/ChIJj61dQgK6j4AR4GeTYWZsKWw. Questo corrisponde al campo del luogo nella richiesta sottostante.
language languageCode Rinominato. Se omesso, la versione v3 utilizza l'intestazione Accept-Language o il valore predefinito en, mentre la versione v4 utilizza per impostazione predefinita la lingua e lo script locali della località.
region regionCode Rinominato. Se omesso, v3 assume il valore predefinito us, mentre v4 non ha un valore predefinito.

Modifiche ai campi di risposta

Campo v3 Campo v4 Note
status, error_message Rimosso La versione 4 utilizza i codici di stato HTTP e i corpi degli errori.
results (root) v4 restituisce un singolo oggetto risultato, non un array results.
results.address_components.long_name/results.address_components.short_name addressComponents.longText/addressComponents.shortText Rinominato.
results.geometry.location_type granularity Rinominato.
results.geometry.location location Nomi dei campi: lat/lng -> latitude/longitude.
results.geometry.viewport viewport Nomi dei campi: northeast/southwest -> high/low.
results.postcode_localities postalCodeLocalities Rinominato. Ora restituito per una o più località (v3 richiede >1).
Novità addressComponents.languageCode Lingua del componente dell'indirizzo specifico.
Novità bounds Limiti espliciti utilizzando high/low.
Novità place Il nome della risorsa per il luogo.
Novità postalAddress Oggetto PostalAddress strutturato.

Esegui la migrazione dai dati iperlocali di geocodifica a Destinations

Le seguenti funzionalità dell'API Geocoding v3 verranno sostituite dal metodo SearchDestinations dell'API Geocoding v4:

  • Entrate
  • Punti di navigazione
  • Contorni degli edifici
  • Terreni

Se utilizzavi l'API Geocoding v3 per le funzionalità precedenti, consulta questo documento per scoprire come utilizzare il metodo SearchDestinations per ottenere queste funzionalità. Questo documento spiega dove trovare queste funzionalità nella risposta SearchDestinations e le differenze nel modo in cui queste funzionalità sono rappresentate nelle risposte dell'API tra l'API Geocoding v3 e il metodo SearchDestinations dell'API Geocoding v4.

Entrate

Per ottenere gli ingressi associati a un destination, utilizza il campo destination.entrances.

Ogni entrance in destination.entrances ha i seguenti campi (che sostituiscono lo schema v3 precedente buildings.entrances):

  • displayName: un nuovo campo facoltativo che contiene un nome leggibile per l'ingresso, ad esempio "Gate B".
  • location: una località di tipo LatLng che utilizza latitude e longitude (sostituendo lat/lng della versione v3).
  • tags: corrisponde al campo tags degli ingressi dell'API Geocoding v3 (ad esempio PREFERRED).
  • place: il nome della risorsa del luogo (ad esempio places/ChIJ...), che sostituisce il campo building_place_id dell'API Geocoding v3. Nella versione 4, questo luogo può rappresentare qualsiasi struttura di destinazione (edificio, campus o parco), non solo un edificio.

Per ottenere i punti di navigazione associati a un destination, utilizza il campo destination.navigationPoints.

Ogni navigationPoint in destination.navigationPoints ha i seguenti campi (che sostituiscono lo schema navigation_points v3 precedente):

  • navigationPointToken: una stringa di token criptata utilizzata per l'instradamento a questo punto di navigazione specifico nel metodo ComputeRoutes dell'API Routes (Waypoint.navigationPointToken). Consulta Percorso utilizzando i token dei punti di navigazione.
  • displayName: un nuovo campo facoltativo che contiene un nome leggibile per il punto di navigazione, ad esempio "5th Ave".
  • location: una località di tipo LatLng utilizzando latitude e longitude.
  • travelModes: simile al campo restricted_travel_modes dell'API Geocoding v3, con la differenza che la v4 specifica le modalità di viaggio accettabili (DRIVE, WALK) anziché quelle limitate.
  • usage: un nuovo campo che specifica i casi d'uso di arrivo supportati per il punto di navigazione (ad esempio PICKUP, DROPOFF o PARKING).

Contorni degli edifici

Per ottenere i contorni degli edifici associati a un destination, utilizza il campo displayPolygon degli oggetti placeView nel destination che rappresentano gli edifici (sostituendo l'array buildings.building_outlines v3 precedente). Per ogni placeView, controlla se si tratta di un edificio con il campo placeView.structureType. Se il tipo di struttura è BUILDING, puoi ottenere il contorno dal campo placeView.displayPolygon. placeView avrà anche campi aggiuntivi per l'edificio che non erano presenti nell'API Geocoding v3.

Un destination può avere un oggetto placeView che rappresenta un edificio nei seguenti campi:

  • destination.primary: il luogo principale della destinazione.
  • destination.containingPlaces: un campo ripetuto che contiene luoghi più grandi che "contengono" il luogo principale. Ad esempio, se il luogo principale è un subpremise, containingPlaces di solito contiene il placeView che rappresenta l'edificio.
  • destination.subDestinations: un campo ripetuto che contiene le destinazioni secondarie del luogo principale (ad esempio, singole unità di appartamenti o suite all'interno di un edificio).

Tieni presente che il formato di placeView.displayPolygon corrisponde al formato del profilo dell'edificio nell'API Geocoding v3, ovvero il formato GeoJSON, utilizzando il formato RFC 7946.

Terreni

Analogamente ai profili degli edifici, per ottenere i terreni associati a un destination, utilizza il campo displayPolygon degli oggetti placeView nel destination che rappresentano i terreni (sostituendo l'array grounds della versione 3 precedente). Per ogni placeView, controlla se si tratta di un poligono di terreno con il campo placeView.structureType. Se il tipo di struttura è GROUNDS, puoi ottenere il contorno dal campo placeView.displayPolygon. placeView avrà anche campi aggiuntivi per i terreni che non erano presenti nell'API Geocoding v3.

Un destination può avere un oggetto placeView che rappresenta un terreno nei seguenti campi:

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

Tieni presente che il formato di placeView.displayPolygon corrisponde al formato del profilo del terreno nell'API Geocoding v3, ovvero il formato GeoJSON, utilizzando il formato RFC 7946.

Precisione dei risultati

Nell'API Geocoding v3, il campo location_type nella geometria della risposta indicava la precisione dei risultati e alcuni client classificavano o filtravano i risultati in base a questi valori (ROOFTOP, RANGE_INTERPOLATED, GEOMETRIC_CENTER e APPROXIMATE). Nelle migrazioni standard all'API Geocoding v4, questo campo viene rinominato granularity.

Nell'API Destinations (v4 SearchDestinations), non esiste un campo location_type. Le informazioni spaziali vengono invece gestite in modo diverso:

  • Nessun filtro lato client manuale necessario: mentre la geocodifica standard fornisce più risultati con granularità diverse, il metodo SearchDestinations riduce al minimo l'ambiguità risolvendo in un'unica destinazione ottimizzata, se possibile. In questo modo, i clienti non devono filtrare per tipo di località per determinare quale risultato è il migliore.
  • Informazioni spaziali rappresentate dal tipo di struttura e dai poligoni di visualizzazione: La geometria e la struttura spaziali sono indicate da:
    • displayPolygon (per la geometria esatta).
    • Il campo structureType all'interno dell'oggetto placeView.
  • Mappatura del tipo di struttura:
    • Un structureType di POINT, BUILDING o SECTION corrisponde generalmente a quello che in precedenza era chiamato ROOFTOP.
    • Un structureType di GROUNDS corrisponde generalmente a GEOMETRIC_CENTER.

Utilizza una maschera di campo per richiedere queste funzionalità

Il metodo SearchDestinations richiede una maschera di campo, come spiegato in Scegli i campi da restituire. La maschera di campo può essere impostata su * per restituire tutti i campi oppure puoi impostarla sui campi specifici che vuoi ricevere. Ad esempio, la seguente richiesta API imposta la maschera di campo per ricevere tutti i campi necessari per ottenere gli ingressi, i punti di navigazione, i contorni degli edifici e i terreni di una destinazione:

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

Ricette di migrazione e pattern di codice comuni

Quando esegui la migrazione di workflow complessi da Geocoding v3 o Geocoding++ a SearchDestinations, utilizza le seguenti formule di codice per estrarre strutture spaziali e di indirizzi comuni.

Estrai il poligono dell'edificio migliore

Se vuoi eseguire il rendering del perimetro dell'edificio per una località o una destinazione:

  1. Controlla se il luogo primary ha structureType === 'BUILDING' e contiene un displayPolygon.
  2. In caso contrario, controlla containingPlaces per trovare l'edificio che lo contiene (utile quando la destinazione principale è una destinazione secondaria di un edificio più grande).
  3. Se non viene trovato alcun edificio di contenimento, controlla subDestinations per vedere se sono elencati singoli edifici.
Esempio di codice 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
Esempio di codice 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;
}

Estrai il contorno del terreno

Se hai bisogno del confine di un complesso di appartamenti, un campus aziendale, un centro commerciale o un parco:

  1. Se il luogo primary rappresenta l'intero complesso (structureType === 'GROUNDS'), utilizza primary.displayPolygon.
  2. Se il luogo primary è un edificio o un ingresso situato all'interno di un complesso più grande, trova l'area circostante in containingPlaces.
Esempio di codice 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
Esempio di codice 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;
}

Seleziona i punti di riferimento per la visualizzazione dell'indirizzo rispetto all'arrivo dell'ultimo miglio

Geocoding v3 address_descriptor ha restituito un enum spatial_relationship (WITHIN, BESIDE, BEHIND, NEAR, ACROSS_THE_ROAD, AROUND_THE_CORNER). In SearchDestinations:

  • Non esiste un enum di relazione non elaborato. Utilizza invece direttamente relationalDescription.text. Contiene frasi localizzate e pronte per la visualizzazione, come "Across from Central Park" o "Behind the convention center". Non anteporre "Near " manualmente.
  • Utilizza tags per selezionare il punto di riferimento giusto per il tuo caso d'uso:
    • ARRIVAL: punti di riferimento iperlocali situati nelle immediate vicinanze, di fronte o dall'altra parte della strada rispetto alla destinazione (in genere entro 50-100 metri). Ideale per l'arrivo del conducente in tempo reale, la conferma di consegna del corriere o le schede di arrivo in-app.
    • ADDRESS: punti di riferimento di rilievo locale nel quartiere circostante (in genere entro 100-500 metri). Ideale per il pagamento rivolto ai clienti, la revisione degli ordini o la disambiguazione della destinazione prima del viaggio.
    • Se un punto di riferimento ha entrambi i tag ADDRESS e ARRIVAL, significa che è molto noto nel quartiere e immediatamente adiacente alla destinazione.
Esempio di codice 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
Esempio di codice 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;
}

Percorso verso i punti di navigazione del veicolo e gli ingressi preferiti

I flussi di lavoro di spedizione e arrivo dell'ultimo miglio combinano due tipi complementari di punti di accesso spaziali:

  • Indicazioni stradali passo passo: indirizza i veicoli verso i punti di arrivo designati sulla strada utilizzando navigationPoints. I punti di navigazione sono pre-classificati in base alla vicinanza e alla pertinenza, quindi il primo candidato con la modalità di viaggio desiderata (ad esempio 'DRIVE') e il tag di utilizzo (ad esempio 'DROPOFF' o 'PICKUP') fornisce il waypoint ottimale per il veicolo. Invia il suo navigationPointToken al metodo ComputeRoutes dell'API Routes (Waypoint.navigationPointToken) o all'SDK di navigazione. Se non esiste un punto di guida agganciato alla strada, utilizza l'ingresso dell'edificio o il centroide principale.
  • Accesso fisico all'ingresso: guida il corriere a piedi o il passeggero fino all'ingresso dell'edificio utilizzando destinations.entrances. Controlla tags per 'PREFERRED' per trovare gli ingressi che probabilmente forniscono un accesso fisico diretto. Se non sono disponibili dati sull'ingresso, utilizza un punto di navigazione pedonale (travelModes incluso 'WALK') o il baricentro principale.
Esempio di codice 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,
    }
Esempio di codice 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,
    };
}

Considerazioni sulla sicurezza

L'API Geocoding v4 è progettata come API server-to-server. Non esiste un percorso di migrazione diretto per gli utenti JavaScript dalla versione 3 alla versione 4. La chiamata dei metodi v4 direttamente da JavaScript lato client (ad esempio, in un browser) utilizzando una chiave API espone la chiave API a un rischio elevato di furto e uso improprio.

Le restrizioni dei referrer HTTP, sebbene utili, non sono una protezione sufficiente per gli endpoint dei servizi web, in quanto possono essere facilmente aggirate da utenti malintenzionati che falsificano l'intestazione Referer nelle loro richieste.

Il modo consigliato per utilizzare l'API Geocoding v4 è dal tuo server di backend. L'applicazione client deve inviare richieste a questo server intermediario, che poi chiama l'API di Google in modo sicuro utilizzando una chiave API protetta (ad esempio, una chiave archiviata in una variabile di ambiente o in un Secret Manager). In questo modo, la chiave API non viene mai esposta nel codice frontend.

Alternative per le esigenze lato client

Se hai esigenze lato client che richiedono la geocodifica, valuta la possibilità di utilizzare una delle soluzioni lato client esistenti:

  • Servizio di geocodifica nell'API Maps JavaScript: il servizio di geocodifica continua a utilizzare il backend v3 ed è progettato per l'utilizzo in un ambiente browser.
  • Places UI Kit: utilizza Places UI Kit, inclusi gli elementi Place Autocomplete, per gli elementi dell'interfaccia utente relativi agli indirizzi.