Migracja z interfejsu Geocoding API w wersji 3 do wersji 4

Deweloperzy z Europejskiego Obszaru Gospodarczego (EOG)

Interfejs Geocoding API w wersji 4 wprowadza kilka nowych metod, które zastępują funkcje interfejsu API w wersji 3. Z tego przewodnika dowiesz się, jak przenieść aplikację, aby korzystała z nowych metod w wersji 4.

Możesz używać dotychczasowych kluczy interfejsu API z nowymi metodami w wersji 4. Jeśli jednak poprosisz o zwiększenie limitu w przypadku interfejsu API w wersji 3, musisz poprosić o zwiększenie limitu w przypadku nowych interfejsów API w wersji 4.

Migracja z geokodowania w wersji 3

Jeśli do geokodowania adresów używasz geokodowania w wersji 3, przejdź na metodę Geokodowanie adresu w wersji 4, która akceptuje żądanie GET.

W interfejsie API w wersji 4 zmieniliśmy nazwy, strukturę i obsługę kilku parametrów. Zdecydowanie zalecamy używanie maski pola, aby określić pola, które mają być zwracane w odpowiedzi.

Zmiany parametru żądania

Parametr wersji 3 Parametr v4 Uwagi
address, components address Nieustrukturyzowany adres (wersja 3 address) jest teraz przekazywany w ścieżce adresu URL. Ustrukturyzowane komponenty adresu (wersja 3 components) można przekazywać jako parametry zapytania address.*. Zobacz Odtwarzanie filtrów komponentów w wersji 3.
bounds locationBias.rectangle Zmieniono nazwę i strukturę na obiekt.
language languageCode Nazwa została zmieniona.
region regionCode Nazwa została zmieniona.
extra_computations Usunięto Zastąpiona przez metodę SearchDestinations.

Zmiany w polu odpowiedzi

Pole w wersji 3 Pole w wersji 4 Uwagi
status, error_message Usunięto Wersja 4 używa kodów stanu HTTP i treści błędów.
results.address_components.long_name/results.address_components.short_name results.addressComponents.longText/results.addressComponents.shortText Nazwa została zmieniona.
results.geometry.location_type results.granularity Nazwa została zmieniona.
results.geometry.location results.location Nazwy pól: lat/lng -> latitude/longitude.
results.geometry.viewport results.viewport Nazwy pól: northeast/southwest -> high/low.
results.postcode_localities results.postalCodeLocalities Nazwa została zmieniona. Obecnie zwracany w przypadku co najmniej 1 lokalizacji (wersja 3 wymaga wartości >1).
results.partial_match Usunięto
Nowość results.addressComponents.languageCode Język konkretnego komponentu adresu.
Nowość results.bounds Jawne granice za pomocą tagów high/low.
Nowość results.place Nazwa zasobu miejsca.
Nowość results.postalAddress Ustrukturyzowany obiekt PostalAddress.

Odtwarzanie filtrów komponentów w wersji 3

Geokodowanie w wersji 3 zawierało parametr components, który umożliwiał dokładne filtrowanie wyników pod kątem określonych komponentów (np. components=country:US). Geokodowanie w wersji 4 nie obsługuje tego typu dokładnego filtrowania w parametrach żądania. W wersji 4 możesz podać informacje o adresie jako pojedynczy nieustrukturyzowany ciąg znaków w ścieżce lub jako parametry zapytania strukturalnego, np. address.addressLines, address.locality, address.administrativeArea, address.postalCodeaddress.regionCode. Parametry strukturalne nie działają jak filtry ścisłe. Zamiast tego wszystkie podane komponenty są łączone w pełny adres, który interfejs API będzie próbował geokodować. Interfejs API wyszukuje najlepsze dopasowanie całego podanego adresu we wszystkich komponentach. Podawanie komponentów w uporządkowany sposób może pomóc interfejsowi API lepiej zrozumieć intencje użytkownika, zwłaszcza gdy informacje o adresie są zbierane z osobnych pól formularza. Może to pomóc interfejsowi API w obsłudze drobnych błędów pisowni lub niejasności w poszczególnych komponentach, ponieważ rodzaj informacji w każdym polu jest jasny.

Aby uzyskać działanie podobne do filtrów komponentów w wersji 3, musisz wdrożyć filtrowanie po stronie klienta na tablicy results zwracanej przez interfejs API w wersji 4 na podstawie obiektów postalAddressaddressComponents w odpowiedzi.

W tabeli poniżej znajdziesz najlepsze dopasowanie między filtrami interfejsu v3 components a polami interfejsu v4 postalAddress:

Filtr komponentów w wersji 3 Pole odpowiedzi w wersji 4
country postalAddress.regionCode
postal_code postalAddress.postalCode
administrative_area postalAddress.administrativeArea lub addressComponents

Przykłady filtrowania po stronie klienta

Poniższe przykłady pokazują, jak filtrować wyniki, aby uzyskać zachowanie podobne do filtrowania komponentów w wersji 3 w przypadku obsługiwanych pól: kraj, obszar administracyjny i kod pocztowy. Nie zalecamy filtrowania według innych pól, ponieważ nie ma wiarygodnych kryteriów filtrowania.

Filtrowanie według kraju

Dopasuj parametr address.regionCode z żądania do parametru postalAddress.regionCode w każdym wyniku. Pamiętaj, że chociaż interfejs API akceptuje w żądaniu kody regionów pisane małymi literami, w odpowiedzi zawsze zwraca je pisane wielkimi literami, więc przed porównaniem musisz znormalizować dane wejściowe do wielkich liter.

Przykład kodu w Pythonie
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')
Przykładowy kod w 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');
Filtrowanie według obszaru administracyjnego

Dopasuj parametr address.administrativeArea z żądania do parametru postalAddress.administrativeArea w każdym wyniku. Podobnie jak w przypadku kodów krajów, przed porównaniem należy znormalizować dane wejściowe do wielkich liter. Jest to wiarygodne tylko wtedy, gdy w żądaniu w przypadku parametru administrativeArea podano standardowy 2-literowy skrót. Z kilku powodów znak postalAddress.administrativeArea w odpowiedzi może nie być bezpośrednio zgodny z sufiksami kodów ISO 3166-2. Po pierwsze, w niektórych regionach podział odpowiadający kodowi ISO 3166-2 nie jest częścią standardowej reprezentacji adresów pocztowych. Na przykład w Hiszpanii obszar administracyjny poziomu 1 (np. „CN” dla Wysp Kanaryjskich) może występować w addressComponents, ale postalAddress.administrativeArea może zawierać obszar poziomu 2 (np. „Santa Cruz de Tenerife”). Po drugie, w niektórych regionach skrót podziału administracyjnego nie jest powszechnie używany i jest reprezentowany w postalAddress.administrativeArea dłuższą nazwą (z podobnych powodów addressComponents.shortText w przypadku komponentu adresu odpowiadającego podziałowi administracyjnemu może nie pasować do sufiksu kodu ISO 3166-2 podziału administracyjnego). Dodatkowo w niektórych przypadkach podział może być reprezentowany w komponencie adresu dla administrative_area_level_n, gdzie n > 1. Aby uzyskać jak najpełniejsze wyniki, sprawdź, czy występuje dopasowanie w przypadku obu elementów postalAddress.administrativeArea i wszystkich elementów addressComponents z typem administrative_area_level_n (np. administrative_area_level_1).

Przykład kodu w Pythonie
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')
Przykładowy kod w 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');
Filtrowanie według kodu pocztowego

Dopasuj parametr address.postalCode z żądania do parametru postalAddress.postalCode w każdym wyniku. Przed porównaniem musisz znormalizować zarówno kod pocztowy wejściowy, jak i wynikowy. Logika normalizacji jest w dużym stopniu uzależniona od regionu. Podstawowe podejście polega na usunięciu spacji i łączników oraz przekształceniu tekstu na jednolity format.

Aby obsługiwać prefiksy kodów pocztowych (np. „L2” w Wielkiej Brytanii) lub sufiksy (np. „+4” w kodach pocztowych w Stanach Zjednoczonych), może być potrzebna bardziej zaawansowana normalizacja. Wymagana logika normalizacji różni się w zależności od kraju i formatów kodów pocztowych. W przypadku regionów, na które kierujesz reklamy, może być konieczne dostosowanie podanych funkcji normalizacji lub wdrożenie bardziej zaawansowanej logiki.

Podany przykład obsługuje amerykańskie kody pocztowe i umożliwia dopasowywanie do 5-cyfrowej podstawy, nawet jeśli podano lub zwrócono kod ZIP+4.

Przykład kodu w Pythonie (skupiony na kodach pocztowych w Stanach Zjednoczonych)
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')
Przykładowy kod w Node.js (skupiony na kodach pocztowych w USA)
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');

Migracja z odwrotnego geokodowania w wersji 3

Jeśli używasz geokodowania zwrotnego w wersji 3 do przekształcania współrzędnych w adresy, musisz przejść na metodę Geokodowanie zwrotne lokalizacji w wersji 4, która akceptuje żądanie GET.

W interfejsie API w wersji 4 zmieniliśmy nazwy, strukturę i obsługę kilku parametrów. Zdecydowanie zalecamy używanie maski pola, aby określić pola, które mają być zwracane w odpowiedzi.

Zmiany parametru żądania

Parametr wersji 3 Parametr v4 Uwagi
language languageCode Nazwa została zmieniona.
region regionCode Nazwa została zmieniona.
result_type types Zmieniono nazwę; używa powtarzanych parametrów zapytania.
location_type granularity Zmieniono nazwę; używa powtarzanych parametrów zapytania.
extra_computations Usunięto Zastąpiona przez metodę SearchDestinations.

Zmiany w polu odpowiedzi

Pole w wersji 3 Pole w wersji 4 Uwagi
status, error_message Usunięto Wersja 4 używa kodów stanu HTTP i treści błędów.
results.address_components.long_name/results.address_components.short_name results.addressComponents.longText/results.addressComponents.shortText Nazwa została zmieniona.
results.geometry.location_type results.granularity Nazwa została zmieniona.
results.geometry.location results.location Nazwy pól: lat/lng -> latitude/longitude.
results.geometry.viewport results.viewport Nazwy pól: northeast/southwest -> high/low.
Nowość results.addressComponents.languageCode Język konkretnego komponentu adresu.
Nowość results.bounds Jawne granice za pomocą tagów high/low.
Nowość results.place Nazwa zasobu miejsca.
Nowość results.postalAddress Ustrukturyzowany obiekt PostalAddress.

Migracja z deskryptorów adresu w wersji 3

Jeśli używasz address_descriptor, aby uzyskać dodatkowe informacje o lokalizacji za pomocą interfejsu Geocoding API w wersji 3, musisz przejść na używanie pola landmarksSearchDestinationsResponse.

Migracja z geokodowania Miejsc w wersji 3

Jeśli używasz place_id do pobierania adresu dla konkretnego identyfikatora miejsca za pomocą interfejsu Geocoding API w wersji 3, musisz przejść na metodę Place Geocoding w wersji 4, która akceptuje żądanie GET.

W interfejsie API w wersji 4 zmieniliśmy nazwy, strukturę i obsługę kilku parametrów. Zdecydowanie zalecamy używanie maski pola, aby określić pola, które mają być zwracane w odpowiedzi.

Zmiany parametru żądania

Parametr wersji 3 Parametr v4 Uwagi
place_id place pole w protokole żądania Identyfikator miejsca jest teraz podawany jako parametr ścieżki places/{place}, np. https://geocode.googleapis.com/v4/geocode/places/ChIJj61dQgK6j4AR4GeTYWZsKWw. Odpowiada to polu miejsca w żądanym zapytaniu.
language languageCode Nazwa została zmieniona.
region regionCode Nazwa została zmieniona.

Zmiany w polu odpowiedzi

Pole w wersji 3 Pole w wersji 4 Uwagi
status, error_message Usunięto Wersja 4 używa kodów stanu HTTP i treści błędów.
results (root) Wersja 4 zwraca pojedynczy obiekt wyniku, a nie tablicę results.
results.address_components.long_name/results.address_components.short_name addressComponents.longText/addressComponents.shortText Nazwa została zmieniona.
results.geometry.location_type granularity Nazwa została zmieniona.
results.geometry.location location Nazwy pól: lat/lng -> latitude/longitude.
results.geometry.viewport viewport Nazwy pól: northeast/southwest -> high/low.
results.postcode_localities postalCodeLocalities Nazwa została zmieniona. Obecnie zwracany w przypadku co najmniej 1 lokalizacji (wersja 3 wymaga wartości >1).
Nowość addressComponents.languageCode Język konkretnego komponentu adresu.
Nowość bounds Jawne granice za pomocą tagów high/low.
Nowość place Nazwa zasobu miejsca.
Nowość postalAddress Ustrukturyzowany obiekt PostalAddress.

Migracja z geokodowania danych hiperlokalnych do miejsc docelowych

Te funkcje interfejsu Geocoding API w wersji 3 są zastępowane przez metodę SearchDestinations interfejsu Geocoding API w wersji 4:

  • Wejścia
  • Punkty nawigacyjne
  • Kontury budynków
  • Tereny posiadłości

Jeśli do obsługi powyższych funkcji używasz interfejsu Geocoding API w wersji 3, zapoznaj się z tym dokumentem, aby dowiedzieć się, jak zamiast niego używać metody SearchDestinations. Z tego dokumentu dowiesz się, gdzie w SearchDestinations odpowiedzi znaleźć te funkcje, oraz poznasz różnice w sposobie ich reprezentowania w odpowiedziach interfejsu API między interfejsem Geocoding API w wersji 3 a metodą SearchDestinations interfejsu Geocoding API w wersji 4.

Wejścia

Aby uzyskać wejścia powiązane z destination, użyj pola destination.entrances.

Zwróć uwagę, że format entrance nieco różni się od formatu wejścia w interfejsie Geocoding API w wersji 3. Każde wejście w destination.entrances ma te pola:

  • displayName – to nowe pole opcjonalne, które będzie zawierać czytelną dla użytkownika nazwę wejścia, np. „Brama B”.
  • location – jest to lokalizacja typu LatLng, która różni się od formatu używanego w interfejsie Geocoding API w wersji 3.
  • tags – to pole jest takie samo jak pole tags w przypadku wejść z interfejsu Geocoding API w wersji 3.
  • place – analogiczne do pola buildingPlaceId w przypadku wejść z interfejsu Geocoding API w wersji 3. Identyfikator miejsca w tym polu może jednak dotyczyć miejsca dowolnego typu, nie tylko budynku.

Aby uzyskać punkty nawigacyjne powiązane z destination, użyj pola destination.navigationPoints.

Pamiętaj, że format a navigationPoint nieco różni się od formatu punktu nawigacyjnego w Geocoding API w wersji 3. Każdy punkt nawigacyjny w destination.navigationPoints ma te pola:

  • displayName – to nowe pole opcjonalne, które będzie zawierać czytelną dla użytkownika nazwę punktu nawigacyjnego, np. „5th Ave”.
  • location – jest to lokalizacja typu LatLng, która różni się od formatu używanego w interfejsie Geocoding API w wersji 3.
  • travelModes – jest to podobne do pola restrictedTravelModes punktów nawigacyjnych z interfejsu Geocoding API w wersji 3. Możliwe wartości wyliczenia są takie same, jedyna różnica polega na tym, że to pole reprezentuje teraz dopuszczalne środki transportu dla punktu nawigacyjnego, a nie środki transportu z ograniczeniami.
  • usage – to nowe pole zawiera przypadki użycia obsługiwane przez punkt nawigacyjny.

Kontury budynków

Aby uzyskać kontury budynków powiązane z destination, użyj pola displayPolygon obiektów placeViewdestination, które reprezentują budynki. W przypadku każdego placeView możesz sprawdzić, czy jest to budynek, korzystając z pola placeView.structureType. Jeśli typ struktury to BUILDING, kontur możesz uzyskać z pola placeView.displayPolygon. placeView będzie też zawierać dodatkowe pola dotyczące budynku, których nie było w interfejsie Geocoding API w wersji 3.

destination może mieć obiekt placeView, który reprezentuje budynek w tych polach:

  • destination.primary – to główne miejsce docelowe.
  • destination.containingPlaces – to pole powtarzane, które może zawierać większe miejsca, które „zawierają” miejsce podstawowe. Jeśli np. głównym miejscem jest subpremise, w containingPlaces zwykle znajduje się placeView, czyli budynek.
  • destination.subDestinations – jest to pole powtarzane, które może zawierać podrzędne miejsca docelowe głównego miejsca. Na przykład poszczególne mieszkania w budynku. To pole zwykle nie zawiera ikony placeView reprezentującej budynek.

Pamiętaj, że format placeView.displayPolygon jest zgodny z formatem konturu budynku w interfejsie Geocoding API w wersji 3, czyli formatem GeoJSON, który korzysta z formatu RFC 7946.

Tereny posiadłości

Podobnie jak w przypadku konturów budynków, aby uzyskać tereny powiązane z destination, użyj pola displayPolygon obiektów placeViewdestination, które reprezentują tereny. W przypadku każdego placeView możesz sprawdzić, czy jest to podstawa, korzystając z pola placeView.structureType. Jeśli typ struktury to GROUNDS, możesz pobrać konspekt z pola placeView.displayPolygon. placeView będzie też zawierać dodatkowe pola dotyczące podstaw, które nie były dostępne w interfejsie Geocoding API w wersji 3.

destination może mieć obiekt placeView, który reprezentuje podstawy w tych polach:

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

Pamiętaj, że format placeView.displayPolygon jest zgodny z formatem konturu terenu w interfejsie Geocoding API w wersji 3, czyli formatem GeoJSON, który korzysta z formatu RFC 7946.

Dokładność wyników

W interfejsie Geocoding API w wersji 3 pole location_type w geometrii odpowiedzi wskazywało precyzję wyników, a niektórzy klienci klasyfikowali lub filtrowali wyniki na podstawie tych wartości (ROOFTOP, RANGE_INTERPOLATED, GEOMETRIC_CENTERAPPROXIMATE). W przypadku standardowych migracji do interfejsu Geocoding API w wersji 4 to pole zmienia nazwę na granularity.

W interfejsie Destinations API (wersja 4 SearchDestinations) nie ma pola location_type. Informacje przestrzenne są obsługiwane w inny sposób:

  • Nie trzeba ręcznie filtrować wyników po stronie klienta: standardowa usługa Geocoding zwraca wiele wyników o różnym poziomie szczegółowości, ale metoda SearchDestinations minimalizuje niejednoznaczność, ponieważ w miarę możliwości podaje tylko jedno, zoptymalizowane miejsce docelowe. Dzięki temu klienci nie muszą filtrować wyników według typu lokalizacji, aby określić, który z nich jest najlepszy.
  • Informacje przestrzenne przedstawione za pomocą typu struktury i wielokątów wyświetlania: geometria przestrzenna i struktura są oznaczone:
    • Symbol displayPolygon (dla dokładnej geometrii).
    • Pole structureType w obiekcie placeView.
  • Mapowanie typu struktury:
    • structureType w przypadku POINT, BUILDING lub SECTION odpowiada zwykle temu, co wcześniej nazywano ROOFTOP.
    • Wartość structureType wynosząca GROUNDS odpowiada zwykleGEOMETRIC_CENTER.

Używanie maski pola do wysyłania próśb o te funkcje

Metoda SearchDestinations wymaga maski pola, co wyjaśniono w artykule Wybieranie pól do zwrócenia. Maskę pola można ustawić na *, aby zwrócić wszystkie pola, lub ustawić ją na konkretne pola, które chcesz otrzymać. Na przykład to żądanie API ustawia maskę pola, aby otrzymać wszystkie pola wymagane do uzyskania wejść, punktów nawigacyjnych, obrysów budynków i terenów miejsca docelowego:

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

Bezpieczeństwo

Geocoding API w wersji 4 to interfejs API działający między serwerami. Użytkownicy JavaScript nie mogą bezpośrednio przejść z wersji 3 na wersję 4. Wywoływanie metod interfejsu API w wersji 4 bezpośrednio z JavaScriptu po stronie klienta (np. w przeglądarce) przy użyciu klucza interfejsu API naraża ten klucz na wysokie ryzyko kradzieży i nadużycia.

Ograniczenia dotyczące odsyłającego HTTP, choć przydatne, nie zapewniają wystarczającej ochrony punktów końcowych usług internetowych, ponieważ mogą być łatwo omijane przez atakujących, którzy fałszują nagłówek Referer w swoich żądaniach.

Zalecany sposób korzystania z interfejsu Geocoding API w wersji 4 to używanie go na własnym serwerze backendu. Aplikacja kliencka powinna wysyłać żądania do tego serwera pośredniczącego, który następnie bezpiecznie wywołuje interfejs API Google za pomocą chronionego klucza interfejsu API (np. klucza przechowywanego w zmiennej środowiskowej lub w usłudze Secret Manager). Dzięki temu klucz interfejsu API nigdy nie będzie widoczny w kodzie interfejsu.

Alternatywne rozwiązania dla potrzeb po stronie klienta

Jeśli masz potrzeby po stronie klienta, które wymagają geokodowania, rozważ użycie jednego z tych rozwiązań po stronie klienta: