Layanan web Google Maps Platform adalah kumpulan antarmuka HTTP ke layanan Google yang menyediakan data geografis untuk aplikasi peta Anda.
Panduan ini menjelaskan beberapa praktik umum yang berguna untuk menyiapkan permintaan layanan web dan memproses respons layanan. Lihat panduan developer untuk dokumentasi lengkap Directions API (Legacy).
Apa yang dimaksud dengan layanan web?
Layanan web Google Maps Platform adalah antarmuka untuk meminta data Maps API dari layanan eksternal dan menggunakan data tersebut dalam aplikasi Maps Anda. Layanan ini dirancang untuk digunakan bersama dengan peta, sesuai dengan Pembatasan Lisensi dalam Persyaratan Layanan Google Maps Platform.
Layanan web Maps API menggunakan permintaan HTTP(S) ke URL tertentu, meneruskan parameter URL dan/atau data POST berformat JSON sebagai argumen ke layanan. Umumnya, layanan ini menampilkan data di isi respons sebagai JSON atau XML untuk diuraikan dan/atau diproses oleh aplikasi Anda.
Permintaan Directions API (Legacy) yang umum biasanya berbentuk sebagai berikut:
https://maps.googleapis.com/maps/api/directions/output?parameters
dengan output menunjukkan format respons (biasanya
json atau xml).
Catatan: Semua aplikasi Directions API (Legacy) memerlukan autentikasi. Dapatkan informasi selengkapnya tentang kredensial autentikasi.
Akses SSL/TLS
HTTPS diperlukan untuk semua permintaan Google Maps Platform yang menggunakan kunci API atau berisi data pengguna. Permintaan yang dibuat melalui HTTP yang berisi data sensitif dapat ditolak.
Membuat URL yang valid
Anda mungkin menganggap URL yang "valid" sudah jelas, tetapi
kenyataannya tidak demikian. URL yang dimasukkan dalam kolom URL di
browser, sebagai contoh, dapat berisi karakter khusus (misalnya
"上海+中國"); browser harus menerjemahkan karakter tersebut secara internal
ke dalam encoding yang berbeda sebelum melakukan transmisi.
Dengan token yang sama, setiap kode yang menghasilkan atau menerima input UTF-8
dapat memperlakukan URL berisi karakter UTF-8 sebagai "valid", tetapi juga perlu
menerjemahkan karakter tersebut sebelum mengirimnya ke server web.
Proses ini disebut
encoding URL atau encoding persen.
Karakter khusus
Karakter khusus harus diterjemahkan karena semua URL harus sesuai dengan sintaksis yang ditentukan oleh spesifikasi Uniform Resource Identifier (URI). Dengan demikian, URL hanya boleh berisi sebagian karakter ASCII khusus: simbol alfanumerik yang sudah umum, dan beberapa karakter dengan fungsi khusus untuk digunakan sebagai karakter kontrol dalam URL. Tabel ini merangkum karakter tersebut:
| Kumpulan | karakter | Penggunaan URL |
|---|---|---|
| Alfanumerik | a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 | String teks, penggunaan skema (http), port (8080), dll. |
| Tanpa fungsi khusus | - _ . ~ | String teks |
| Dengan fungsi khusus | ! * ' ( ) ; : @ & = + $ , / ? % # [ ] | Karakter kontrol dan/atau String Teks |
Saat membuat URL yang valid, Anda harus memastikan bahwa URL tersebut hanya berisi karakter yang ditampilkan dalam tabel. Penyesuaian URL untuk menggunakan kumpulan karakter ini biasanya menyebabkan dua masalah, yaitu masalah penghilangan dan masalah penggantian:
- Karakter yang ingin Anda tangani tidak termasuk dalam
kumpulan karakter di atas. Misalnya, karakter dalam bahasa asing
seperti
上海+中國harus dienkode menggunakan karakter di atas. Menurut aturan umum, spasi (yang tidak diizinkan dalam URL) sering kali juga dinyatakan menggunakan karakter plus'+'. - Karakter yang ada dalam kumpulan di atas merupakan karakter dengan fungsi khusus, tetapi harus digunakan secara literal.
Misalnya,
?digunakan dalam URL untuk menunjukkan awal dari string kueri; jika Anda ingin menggunakan string "? and the Mysterians", Anda harus mengenkode karakter'?'.
Semua karakter yang akan dienkode ke URL dienkode
menggunakan karakter '%' dan nilai heksadesimal dua karakter
yang sesuai dengan karakter UTF-8. Misalnya,
上海+中國 di UTF-8 akan dienkode ke URL sebagai
%E4%B8%8A%E6%B5%B7%2B%E4%B8%AD%E5%9C%8B. String
? and the Mysterians akan dienkode ke URL sebagai
%3F+and+the+Mysterians atau %3F%20and%20the%20Mysterians.
Karakter umum yang memerlukan encoding
Beberapa karakter umum yang harus dienkode adalah:
| Karakter tidak aman | Nilai yang dienkode |
|---|---|
| Spasi | %20 |
| " | %22 |
| < | %3C |
| > | %3E |
| # | %23 |
| % | %25 |
| | | %7C |
Mengonversi URL yang Anda terima dari input pengguna terkadang rumit. Misalnya, seorang pengguna dapat memasukkan alamat sebagai "5th&Main St." Biasanya, Anda harus membuat URL Anda dari bagian-bagiannya, memperlakukan setiap input pengguna sebagai karakter literal.
Selain itu, URL dibatasi hingga 16.384 karakter untuk semua layanan web Google Maps Platform dan Static Web API. Untuk sebagian besar layanan, batas karakter ini jarang tercapai. Namun, perhatikan bahwa layanan tertentu memiliki beberapa parameter yang dapat menghasilkan URL panjang.
Penggunaan Moderat Google API
Klien API yang didesain dengan buruk dapat memberikan beban yang lebih besar dari yang diperlukan pada Internet dan server Google. Bagian ini berisi beberapa praktik terbaik untuk klien API. Mengikuti praktik terbaik ini dapat membantu Anda menghindari pemblokiran aplikasi karena penyalahgunaan API yang tidak disengaja.
Backoff Eksponensial
Dalam kasus yang jarang terjadi, ada yang mungkin salah saat melayani permintaan Anda; Anda mungkin menerima kode respons HTTP 4XX atau 5XX, atau koneksi TCP mungkin gagal di suatu tempat antara klien Anda dan server Google. Sering kali permintaan perlu dicoba lagi karena permintaan lanjutan mungkin berhasil saat permintaan asli gagal. Namun, penting untuk tidak hanya melakukan permintaan berulang kali ke server Google. Perilaku perulangan ini dapat membebani jaringan antara klien dan Google, sehingga menyebabkan masalah bagi banyak pihak.
Pendekatan terbaik adalah mencoba ulang dengan meningkatkan waktu tunda antar percobaan. Biasanya, penundaan ditingkatkan dengan faktor perkalian pada setiap percobaan, sebuah pendekatan yang dikenal sebagai Exponential Backoff.
Misalnya, pertimbangkan aplikasi yang ingin membuat permintaan ini ke Time Zone API:
https://maps.googleapis.com/maps/api/timezone/json?location=39.6034810,-119.6822510×tamp=1331161200&key=YOUR_API_KEYContoh Python berikut menampilkan cara membuat permintaan dengan backoff eksponensial:
import json import time import urllib.error import urllib.parse import urllib.request # The maps_key defined below isn't a valid Google Maps API key. # You need to get your own API key. # See https://developers.google.com/maps/documentation/timezone/get-api-key API_KEY = "YOUR_KEY_HERE" TIMEZONE_BASE_URL = "https://maps.googleapis.com/maps/api/timezone/json" def timezone(lat, lng, timestamp): # Join the parts of the URL together into one string. params = urllib.parse.urlencode( {"location": f"{lat},{lng}", "timestamp": timestamp, "key": API_KEY,} ) url = f"{TIMEZONE_BASE_URL}?{params}" current_delay = 0.1 # Set the initial retry delay to 100ms. max_delay = 5 # Set the maximum retry delay to 5 seconds. while True: try: # Get the API response. response = urllib.request.urlopen(url) except urllib.error.URLError: pass # Fall through to the retry loop. else: # If we didn't get an IOError then parse the result. result = json.load(response) if result["status"] == "OK": return result["timeZoneId"] elif result["status"] != "UNKNOWN_ERROR": # Many API errors cannot be fixed by a retry, e.g. INVALID_REQUEST or # ZERO_RESULTS. There is no point retrying these requests. raise Exception(result["error_message"]) if current_delay > max_delay: raise Exception("Too many retry attempts.") print("Waiting", current_delay, "seconds before retrying.") time.sleep(current_delay) current_delay *= 2 # Increase the delay each time we retry. if __name__ == "__main__": tz = timezone(39.6034810, -119.6822510, 1331161200) print(f"Timezone: {tz}")
Anda juga harus berhati-hati agar tidak ada kode percobaan ulang yang lebih tinggi dalam rantai panggilan aplikasi yang menyebabkan permintaan berulang secara berurutan dengan cepat.
Permintaan yang Disinkronkan
Sejumlah besar permintaan yang disinkronkan ke API Google dapat terlihat seperti serangan Distributed Denial of Service (DDoS) pada infrastruktur Google, dan akan ditangani sebagaimana mestinya. Untuk menghindari hal ini, Anda harus memastikan bahwa permintaan API tidak disinkronkan di antara klien.
Misalnya, pertimbangkan aplikasi yang menampilkan waktu dalam zona waktu saat ini. Aplikasi ini mungkin akan menyetel alarm di sistem operasi klien yang akan mengaktifkannya pada awal menit sehingga waktu yang ditampilkan dapat diperbarui. Aplikasi tidak boleh melakukan panggilan API apa pun sebagai bagian dari pemrosesan yang terkait dengan alarm tersebut.
Melakukan panggilan API sebagai respons terhadap alarm tetap tidak baik karena menyebabkan panggilan API disinkronkan dengan awal menit, bahkan di antara perangkat yang berbeda, bukan didistribusikan secara merata dari waktu ke waktu. Aplikasi yang didesain dengan buruk yang melakukan hal ini akan menghasilkan lonjakan traffic hingga enam puluh kali lipat dari tingkat normal di awal setiap menit.
Sebagai gantinya, satu rancangan yang mungkin baik adalah menyetel alarm kedua ke waktu terpilih yang acak. Saat alarm kedua ini diaktifkan, aplikasi akan memanggil API yang diperlukan dan menyimpan hasilnya. Saat aplikasi ingin memperbarui tampilannya di awal menit, aplikasi menggunakan hasil yang disimpan sebelumnya, bukan memanggil API lagi. Dengan pendekatan ini, panggilan API didistribusikan secara merata dari waktu ke waktu. Selain itu, panggilan API tidak menunda rendering saat tampilan sedang diperbarui.
Selain awal menit, waktu sinkronisasi umum lainnya yang harus Anda hindari tidak ditargetkan adalah di awal jam, dan awal setiap hari pada tengah malam.
Memproses Respons
Bagian ini membahas cara mengekstrak nilai-nilai ini secara dinamis dari respons layanan web.
Layanan web Google Maps memberikan respons yang mudah dipahami, tetapi tidak terlalu mudah digunakan. Saat melakukan kueri, daripada menampilkan sekumpulan data, Anda mungkin ingin mengekstrak beberapa nilai tertentu. Biasanya, Anda ingin mengurai respons dari layanan web dan mengekstrak hanya nilai yang Anda minati.
Skema parsing yang Anda gunakan bergantung pada apakah Anda menampilkan output dalam XML atau JSON. Respons JSON, yang sudah dalam bentuk objek Javascript, dapat diproses dalam Javascript itu sendiri di klien. Respons XML harus diproses menggunakan prosesor XML dan bahasa kueri XML untuk menangani elemen dalam format XML. Kami menggunakan XPath dalam contoh berikut, karena umumnya didukung di library pemrosesan XML.
Memproses XML dengan XPath
XML adalah format informasi terstruktur yang relatif matang dan digunakan untuk
pertukaran data. Meskipun tidak seringan JSON, XML
memberikan dukungan bahasa dan alat yang lebih andal. Kode untuk
memproses XML di Java, misalnya, dibuat ke dalam paket
javax.xml.
Saat memproses respons XML, Anda harus menggunakan bahasa kueri yang sesuai untuk memilih node dalam dokumen XML, daripada mengasumsikan elemen berada di posisi absolut dalam markup XML. XPath adalah sintaks bahasa untuk mendeskripsikan node dan elemen secara unik dalam dokumen XML. Ekspresi XPath memungkinkan Anda mengidentifikasi konten tertentu dalam dokumen respons XML.
Ekspresi XPath
Sedikit pemahaman tentang XPath sangat membantu dalam mengembangkan skema penguraian yang andal. Bagian ini akan berfokus pada cara elemen dalam dokumen XML diakses dengan XPath, sehingga Anda dapat mengakses beberapa elemen dan membuat kueri yang kompleks.
XPath menggunakan ekspresi untuk memilih elemen dalam dokumen XML, menggunakan sintaksis yang mirip dengan yang digunakan untuk jalur direktori. Ekspresi ini mengidentifikasi elemen dalam hierarki dokumen XML, yang merupakan hierarki serupa dengan DOM. Umumnya, ekspresi XPath bersifat berlebihan, yang menunjukkan bahwa ekspresi tersebut akan mencocokkan semua node yang cocok dengan kriteria yang diberikan.
Kita akan menggunakan XML abstrak berikut untuk mengilustrasikan contoh kita:
<WebServiceResponse> <status>OK</status> <result> <type>sample</type> <name>Sample XML</name> <location> <lat>37.4217550</lat> <lng>-122.0846330</lng> </location> </result> <result> <message>The secret message</message> </result> </WebServiceResponse>
Pilihan Simpul dalam Ekspresi
Pilihan XPath memilih node. Node root
mencakup seluruh dokumen. Anda memilih node ini menggunakan
ekspresi khusus "/". Perhatikan bahwa node
root bukanlah node tingkat teratas dokumen XML Anda; sebenarnya,
node ini berada satu tingkat di atas elemen tingkat teratas ini dan menyertakannya.
Node elemen merepresentasikan berbagai elemen dalam hierarki dokumen XML. Elemen <WebServiceResponse>, misalnya, merepresentasikan elemen tingkat teratas yang ditampilkan dalam contoh layanan di atas. Anda memilih masing-masing node melalui jalur absolut atau relatif, yang ditunjukkan oleh ada atau tidak adanya karakter "/" di awal.
- Jalur absolut: ekspresi "
/WebServiceResponse/result" memilih semua node<result>yang merupakan turunan dari node<WebServiceResponse>. (Perhatikan bahwa kedua elemen ini berasal dari root node "/".) - Jalur relatif dari konteks saat ini: ekspresi
"
result" akan cocok dengan elemen<result>apa pun dalam konteks saat ini. Biasanya, Anda tidak perlu mengkhawatirkan konteks, karena Anda biasanya memproses hasil layanan web melalui satu ekspresi.
Salah satu ekspresi ini dapat ditambah melalui penambahan
jalur karakter pengganti, yang ditunjukkan dengan garis miring ganda ("//").
Karakter pengganti ini menunjukkan bahwa nol atau beberapa elemen dapat cocok di
jalur yang berada di antara. Ekspresi XPath "//formatted_address",
misalnya, akan cocok dengan semua node dengan nama tersebut dalam dokumen saat ini.
Ekspresi //viewport//lat akan cocok dengan semua elemen <lat> yang dapat melacak <viewport> sebagai induk.
Secara default, ekspresi XPath cocok dengan semua elemen. Anda dapat membatasi
ekspresi agar cocok dengan elemen tertentu dengan memberikan predikat,
yang diapit dalam tanda kurung siku ([]). Misalnya, ekspresi
XPath "/GeocodeResponse/result[2] selalu menampilkan
hasil kedua.
| Tipe Ekspresi | |
|---|---|
| Simpul akar | Ekspresi XPath: "
/"Pilihan:
<WebServiceResponse>
<status>OK</status>
<result>
<type>sample</type>
<name>Sample XML</name>
<location>
<lat>37.4217550</lat>
<lng>-122.0846330</lng>
</location>
</result>
<result>
<message>The secret message</message>
</result>
</WebServiceResponse>
|
| Jalur Absolut | Ekspresi XPath: "
/WebServiceResponse/result"Pilihan:
<result>
<type>sample</type>
<name>Sample XML</name>
<location>
<lat>37.4217550</lat>
<lng>-122.0846330</lng>
</location>
</result>
<result>
<message>The secret message</message>
</result>
|
| Jalur dengan Karakter Pengganti | Ekspresi XPath: "
/WebServiceResponse//location"Pilihan:
<location>
<lat>37.4217550</lat>
<lng>-122.0846330</lng>
</location>
|
| Jalur dengan Predikat | Ekspresi XPath: "
/WebServiceResponse/result[2]/message"Pilihan:
<message>The secret message</message>
|
Semua turunan langsung dari result pertama |
Ekspresi XPath: "
/WebServiceResponse/result[1]/*"Pilihan:
<type>sample</type>
<name>Sample XML</name>
<location>
<lat>37.4217550</lat>
<lng>-122.0846330</lng>
</location>
|
name dari
result yang teks type-nya adalah "sample". |
Ekspresi XPath: "
/WebServiceResponse/result[type/text()='sample']/name"Pilihan:
Sample XML
|
Penting untuk diperhatikan bahwa saat memilih elemen, Anda memilih node, bukan hanya teks dalam objek tersebut. Biasanya, Anda ingin melakukan iterasi pada semua node yang cocok dan mengekstrak teksnya. Anda juga dapat mencocokkan node teks secara langsung; lihat Node Teks di bawah.
Perhatikan bahwa XPath juga mendukung node atribut; namun, semua layanan web Google Maps menyajikan elemen tanpa atribut, sehingga pencocokan atribut tidak diperlukan.
Pemilihan Teks dalam Ekspresi
Teks dalam dokumen XML ditentukan dalam ekspresi XPath
melalui operator node teks. Operator "text()" ini
menunjukkan ekstraksi teks dari node yang ditunjukkan. Misalnya,
ekspresi XPath "//formatted_address/text()" akan
menampilkan semua teks dalam elemen
<formatted_address>.
| Tipe Ekspresi | |
|---|---|
| Semua simpul teks (termasuk spasi) | Ekspresi XPath: "
//text()"Pilihan:
sample
Sample XML
37.4217550
-122.0846330
The secret message
|
| Pemilihan Teks | Ekspresi XPath: "
/WebServiceRequest/result[2]/message/text()"Pilihan:
The secret message
|
| Pilihan Sesuai Konteks | Ekspresi XPath: "
/WebServiceRequest/result[type/text() = 'sample']/name/text()"Pilihan:
Sample XML
|
Atau, Anda dapat mengevaluasi ekspresi dan menampilkan sekumpulan node, lalu melakukan iterasi pada "kumpulan node" tersebut, dengan mengekstrak teks dari setiap node. Kami menggunakan pendekatan ini dalam contoh di bawah.
Untuk mengetahui informasi selengkapnya tentang XPath, lihat Spesifikasi W3C XPath.
Mengevaluasi XPath di Java
Java memiliki dukungan luas untuk mengurai XML dan menggunakan ekspresi XPath dalam paket javax.xml.xpath.*.
Oleh karena itu, contoh kode di bagian ini menggunakan Java untuk
mengilustrasikan cara menangani XML dan mengurai data dari respons layanan XML.
Untuk menggunakan XPath dalam kode Java, Anda harus membuat instance
XPathFactory terlebih dahulu dan memanggil
newXPath() di factory tersebut untuk membuat objek XPath
. Objek ini kemudian dapat memproses ekspresi XML dan XPath yang diteruskan menggunakan metode evaluate().
Saat mengevaluasi ekspresi XPath, pastikan Anda melakukan iterasi
atas kemungkinan "set node" yang dapat ditampilkan. Karena hasil ini ditampilkan sebagai node DOM dalam kode Java, Anda harus mengambil beberapa nilai tersebut dalam objek NodeList dan melakukan iterasi pada objek tersebut untuk mengekstrak teks atau nilai dari node tersebut.
Kode berikut mengilustrasikan cara membuat objek XPath, menetapkan XML dan ekspresi XPath, serta mengevaluasi ekspresi untuk mencetak konten yang relevan.
import org.xml.sax.InputSource; import org.w3c.dom.*; import javax.xml.xpath.*; import java.io.*; public class SimpleParser { public static void main(String[] args) throws IOException { XPathFactory factory = XPathFactory.newInstance(); XPath xpath = factory.newXPath(); try { System.out.print("Web Service Parser 1.0\n"); // In practice, you'd retrieve your XML via an HTTP request. // Here we simply access an existing file. File xmlFile = new File("XML_FILE"); // The xpath evaluator requires the XML be in the format of an InputSource InputSource inputXml = new InputSource(new FileInputStream(xmlFile)); // Because the evaluator may return multiple entries, we specify that the expression // return a NODESET and place the result in a NodeList. NodeList nodes = (NodeList) xpath.evaluate("XPATH_EXPRESSION", inputXml, XPathConstants.NODESET); // We can then iterate over the NodeList and extract the content via getTextContent(). // NOTE: this will only return text for element nodes at the returned context. for (int i = 0, n = nodes.getLength(); i < n; i++) { String nodeString = nodes.item(i).getTextContent(); System.out.print(nodeString); System.out.print("\n"); } } catch (XPathExpressionException ex) { System.out.print("XPath Error"); } catch (FileNotFoundException ex) { System.out.print("File Error"); } } }