Google Haritalar Platformu web hizmetleri, harita uygulamalarınız için coğrafi veriler sağlayan Google hizmetlerine yönelik bir HTTP arayüzleri koleksiyonudur.
Bu kılavuzda, web hizmeti isteklerinizi ayarlamak ve hizmet yanıtlarını işlemek için faydalı olan bazı yaygın uygulamalar açıklanmaktadır. Directions API (Legacy) ile ilgili tüm belgeler için geliştirici kılavuzuna bakın.
Web hizmeti nedir?
Google Haritalar Platformu web hizmetleri, harici hizmetlerden Maps API verilerini istemek ve bu verileri Haritalar uygulamalarınızda kullanmak için bir arayüzdür. Bu hizmetler, Google Haritalar Platformu Hizmet Şartları'ndaki Lisans Kısıtlamaları uyarınca bir haritayla birlikte kullanılmak üzere tasarlanmıştır.
Maps API'leri web hizmetleri, belirli URL'lere HTTP(S) istekleri göndererek URL parametrelerini ve/veya JSON biçimli POST verilerini hizmetlere bağımsız değişken olarak iletir. Genellikle bu hizmetler, uygulamanız tarafından ayrıştırılmak ve/veya işlenmek üzere yanıt gövdesindeki verileri JSON veya XML olarak döndürür.
Tipik bir Directions API (Legacy) isteği genellikle aşağıdaki biçimdedir:
https://maps.googleapis.com/maps/api/directions/output?parameters
Burada output, yanıt biçimini (genellikle json veya xml) gösterir.
Not: Tüm Directions API (Legacy) uygulamaları için kimlik doğrulama gerekir. Kimlik doğrulama kimlik bilgileri hakkında daha fazla bilgi edinin.
SSL/TLS Erişimi
API anahtarlarının kullanıldığı veya kullanıcı verilerinin yer aldığı tüm Google Haritalar Platformu istekleri için HTTPS gereklidir. Hassas veriler içeren HTTP üzerinden yapılan istekler reddedilebilir.
Geçerli bir URL oluşturma
"Geçerli" bir URL'nin ne anlama geldiği açıkça anlaşılıyor gibi görünse de durum tam olarak böyle değildir. Örneğin, bir tarayıcıdaki adres çubuğuna girilen bir URL özel karakterler (ör."上海+中國") içerebilir. Tarayıcının, bu karakterleri iletimden önce farklı bir kodlamaya çevirmesi gerekir.
Aynı şekilde, UTF-8 girişi oluşturan veya kabul eden tüm kodlar, UTF-8 karakterleri içeren URL'leri "geçerli" olarak değerlendirebilir ancak bunları bir web sunucusuna göndermeden önce çevirmesi gerekir.
Bu işleme
URL kodlama veya yüzde kodlama denir.
Özel karakterler
Tüm URL'lerin Tekdüzen Kaynak Tanımlayıcı (URI) spesifikasyonunda belirtilen söz dizimine uyması gerektiğinden özel karakterleri çevirmemiz gerekir. Bu, URL'lerin yalnızca ASCII karakterlerinin özel bir alt kümesini içermesi gerektiği anlamına gelir: tanıdık alfanümerik semboller ve URL'lerde kontrol karakterleri olarak kullanılmak üzere ayrılmış bazı karakterler. Bu karakterler aşağıdaki tabloda özetlenmiştir:
| Ayarlandı | karakterler | URL kullanımı |
|---|---|---|
| Alfanümerik | 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 | Metin dizeleri, şema kullanımı (http), bağlantı noktası (8080) vb. |
| Ayrılmamış | - _ . ~ | Metin dizeleri |
| Rezervasyon yapıldı | ! * ' ( ) ; : @ & = + $ , / ? % # [ ] | Kontrol karakterleri ve/veya metin dizeleri |
Geçerli bir URL oluştururken yalnızca tabloda gösterilen karakterleri içerdiğinden emin olmanız gerekir. Bir URL'nin bu karakter kümesini kullanacak şekilde uyarlanması genellikle iki soruna yol açar: biri eksiklik, diğeri ise değiştirme.
- İşlemek istediğiniz karakterler yukarıdaki kümenin dışında yer alıyor. Örneğin,
上海+中國gibi yabancı dillerdeki karakterlerin yukarıdaki karakterler kullanılarak kodlanması gerekir. Yaygın olarak kabul edilen kurala göre, URL'lerde izin verilmeyen boşluklar genellikle artı'+'karakteriyle de gösterilir. - Yukarıdaki kümede ayrılmış karakterler bulunur ancak bunların olduğu gibi kullanılması gerekir.
Örneğin,
?, sorgu dizesinin başlangıcını belirtmek için URL'lerde kullanılır. "? and the Mysterions" dizesini kullanmak istiyorsanız?karakterini kodlamanız gerekir.'?'
URL kodlaması yapılacak tüm karakterler, '%' karakteri ve UTF-8 karakterlerine karşılık gelen iki karakterli onaltılık değer kullanılarak kodlanır. Örneğin, UTF-8'deki 上海+中國, URL olarak %E4%B8%8A%E6%B5%B7%2B%E4%B8%AD%E5%9C%8B şeklinde kodlanır. ? and the Mysterians dizesi, %3F+and+the+Mysterians veya %3F%20and%20the%20Mysterians olarak URL kodlamalı olur.
Kodlama gerektiren yaygın karakterler
Kodlanması gereken bazı yaygın karakterler şunlardır:
| Güvenli olmayan karakter | Kodlanmış değer |
|---|---|
| Boşluk | %20 |
| " | %22 |
| < | %3C |
| > | %3E |
| # | %23 |
| % | %25 |
| | | %7C |
Kullanıcı girişinden aldığınız bir URL'yi dönüştürmek bazen zor olabilir. Örneğin, bir kullanıcı adresi "5th&Main St." olarak girebilir. Genel olarak, URL'nizi parçalarından oluşturmalı ve kullanıcı girişlerini değişmez karakterler olarak ele almalısınız.
Ayrıca, tüm Google Haritalar Platformu web hizmetleri ve statik web API'leri için URL'ler 16.384 karakterle sınırlıdır. Çoğu hizmette bu karakter sınırına nadiren yaklaşılır. Ancak, belirli hizmetlerin uzun URL'lere neden olabilecek çeşitli parametreleri olduğunu unutmayın.
Google API'lerinin Uygun Kullanımı
Kötü tasarlanmış API istemcileri hem internete hem de Google'ın sunucularına gereğinden fazla yük bindirebilir. Bu bölümde, API istemcileri için bazı en iyi uygulamalar yer almaktadır. Bu en iyi uygulamalara uyarak uygulamanızın API'lerin yanlışlıkla kötüye kullanılması nedeniyle engellenmesini önleyebilirsiniz.
Üstel Geri Alma
Nadir durumlarda isteğinizin sunulmasıyla ilgili bir sorun oluşabilir. Bu durumda 4XX veya 5XX HTTP yanıt kodu alabilir ya da TCP bağlantısı, istemciniz ile Google'ın sunucusu arasında bir yerde başarısız olabilir. İlk istek başarısız olduğunda takip isteği başarılı olabileceğinden isteği yeniden denemek genellikle faydalıdır. Ancak Google'ın sunucularına tekrar tekrar istekte bulunmamak önemlidir. Bu döngü davranışı, istemciniz ile Google arasındaki ağı aşırı yükleyerek birçok taraf için sorunlara neden olabilir.
Daha iyi bir yaklaşım, denemeler arasındaki gecikmeleri artırarak yeniden denemektir. Genellikle gecikme, her denemede çarpımsal bir faktörle artırılır. Bu yaklaşım eksponansiyel geri yükleme olarak bilinir.
Örneğin, Time Zone API'ye şu isteği göndermek isteyen bir uygulamayı ele alalım:
https://maps.googleapis.com/maps/api/timezone/json?location=39.6034810,-119.6822510×tamp=1331161200&key=YOUR_API_KEYAşağıdaki Python örneğinde, eksponansiyel geri yükleme ile isteğin nasıl yapılacağı gösterilmektedir:
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}")
Ayrıca, uygulama çağrısı zincirinde daha yüksek bir yeniden deneme kodu olmadığından emin olmalısınız. Bu kod, hızlı bir şekilde tekrarlanan isteklere yol açar.
Senkronize İstekler
Google'ın API'lerine yapılan çok sayıda senkronize istek, Google'ın altyapısına yönelik bir dağıtılmış hizmet reddi (DDoS) saldırısı gibi görünebilir ve buna göre işlem görebilir. Bunu önlemek için API isteklerinin istemciler arasında senkronize edilmediğinden emin olmanız gerekir.
Örneğin, saati geçerli saat diliminde gösteren bir uygulamayı ele alalım. Bu uygulama, görüntülenen saatin güncellenebilmesi için istemci işletim sisteminde dakikanın başında sistemi uyandıran bir alarm ayarlayabilir. Uygulama, bu alarm ile ilişkili işlem kapsamında herhangi bir API çağrısı yapmamalıdır.
Sabit bir alarma yanıt olarak API çağrıları yapmak, API çağrılarının zaman içinde eşit olarak dağıtılması yerine farklı cihazlar arasında bile dakikanın başlangıcına senkronize edilmesine neden olduğundan kötü bir uygulamadır. Bunu yapan kötü tasarlanmış bir uygulama, her dakikanın başında normal seviyenin altmış katı kadar trafik artışına neden olur.
Bunun yerine, rastgele seçilmiş bir zamanda çalacak ikinci bir alarm ayarlamak iyi bir tasarım olabilir. Bu ikinci alarm tetiklendiğinde uygulama, ihtiyaç duyduğu API'leri çağırır ve sonuçları depolar. Uygulama, dakikanın başında ekranını güncellemek istediğinde API'yi tekrar çağırmak yerine daha önce depolanmış sonuçları kullanır. Bu yaklaşımla API çağrıları zaman içinde eşit olarak dağıtılır. Ayrıca, API çağrıları, ekran güncellenirken oluşturmayı geciktirmez.
Dakikanın başlangıcı dışında, hedeflememeye dikkat etmeniz gereken diğer yaygın senkronizasyon zamanları arasında saatin başlangıcı ve her gün gece yarısı başlangıcı yer alır.
Yanıtları işleme
Bu bölümde, bu değerlerin web hizmeti yanıtlarından dinamik olarak nasıl çıkarılacağı açıklanmaktadır.
Google Haritalar web hizmetleri, anlaşılması kolay ancak tam olarak kullanıcı dostu olmayan yanıtlar sağlar. Sorgu yaparken bir veri kümesi görüntülemek yerine belirli birkaç değeri çıkarmak isteyebilirsiniz. Genellikle, web hizmetinden gelen yanıtları ayrıştırmak ve yalnızca ilgilendiğiniz değerleri ayıklamak istersiniz.
Kullandığınız ayrıştırma şeması, çıkışı XML veya JSON olarak döndürüp döndürmediğinize bağlıdır. Zaten JavaScript nesneleri biçiminde olan JSON yanıtları, istemcide JavaScript'in kendisinde işlenebilir. XML yanıtları, XML biçimindeki öğeleri ele almak için bir XML işlemcisi ve XML sorgu dili kullanılarak işlenmelidir. XML işleme kitaplıklarında yaygın olarak desteklendiği için aşağıdaki örneklerde XPath kullanıyoruz.
XPath ile XML işleme
XML, veri değişimi için kullanılan, nispeten olgun bir yapılandırılmış bilgi biçimidir. XML, JSON kadar hafif olmasa da daha fazla dil desteği ve daha sağlam araçlar sunar. Örneğin, Java'da XML'yi işleme kodu javax.xml paketlerine yerleştirilmiştir.
XML yanıtlarını işlerken XML belgesindeki düğümleri seçmek için uygun bir sorgu dili kullanmanız gerekir. Öğelerin XML işaretlemesi içinde mutlak konumlarda bulunduğunu varsaymamalısınız. XPath, bir XML belgesindeki düğümleri ve öğeleri benzersiz şekilde tanımlamak için kullanılan bir dil söz dizimidir. XPath ifadeleri, XML yanıt dokümanındaki belirli içerikleri tanımlamanıza olanak tanır.
XPath İfadeleri
XPath'e aşina olmak, sağlam bir ayrıştırma şeması geliştirmenize büyük ölçüde yardımcı olur. Bu bölümde, bir XML belgesindeki öğelerin XPath ile nasıl ele alındığına odaklanılacak. Böylece, birden fazla öğeyi ele alabilir ve karmaşık sorgular oluşturabilirsiniz.
XPath, XML belgesindeki öğeleri seçmek için ifadeler kullanır. Bu ifadeler, dizin yolları için kullanılan söz dizimine benzer bir söz dizimi kullanır. Bu ifadeler, bir XML belgesi ağacındaki öğeleri tanımlar. Bu ağaç, DOM'a benzer hiyerarşik bir ağaçtır. Genel olarak XPath ifadeleri, sağlanan ölçütlerle eşleşen tüm düğümlerle eşleşeceklerini belirten açgözlü ifadelerdir.
Örneklerimizi göstermek için aşağıdaki soyut XML'yi kullanacağız:
<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>
İfadelerde Düğüm Seçimi
XPath seçimleri düğümleri seçer. Kök düğüm, dokümanın tamamını kapsar. Bu düğümü "/" özel ifadesini kullanarak seçersiniz. Kök düğümün, XML dokümanınızın üst düzey düğümü olmadığını unutmayın. Aslında bu düğüm, üst düzey öğenin bir seviye üzerinde yer alır ve bu öğeyi içerir.
Öğe düğümleri, XML belge ağacındaki çeşitli öğeleri temsil eder. Örneğin, bir <WebServiceResponse> öğesi, yukarıdaki örnek hizmetimizde döndürülen üst düzey öğeyi temsil eder. Mutlak veya göreli yollar aracılığıyla tek tek düğümler seçersiniz. Bu yollar, başında "/" karakterinin olup olmamasıyla belirtilir.
- Mutlak yol: "
/WebServiceResponse/result" ifadesi,<WebServiceResponse>düğümünün alt öğeleri olan tüm<result>düğümlerini seçer. (Bu öğelerin her ikisinin de kök düğüm "/"den türediğini unutmayın.) - Geçerli bağlamdaki göreli yol: "
result" ifadesi, geçerli bağlamdaki tüm<result>öğeleriyle eşleşir. Genellikle web hizmeti sonuçlarını tek bir ifadeyle işlediğiniz için bağlam konusunda endişelenmenize gerek yoktur.
Bu ifadelerin her ikisi de çift eğik çizgi ("//") ile belirtilen bir joker karakter yolu eklenerek genişletilebilir. Bu joker karakter, aradaki yolda sıfır veya daha fazla öğenin eşleşebileceğini gösterir. Örneğin,"//formatted_address" XPath ifadesi, geçerli belgedeki bu ada sahip tüm düğümlerle eşleşir.
//viewport//lat ifadesi, üst öğe olarak <viewport> öğesini izleyebilen tüm <lat> öğeleriyle eşleşir.
Varsayılan olarak, XPath ifadeleri tüm öğelerle eşleşir. Köşeli parantez ([]) içine alınmış bir yüklem sağlayarak ifadenin belirli bir öğeyle eşleşmesini kısıtlayabilirsiniz. Örneğin, "/GeocodeResponse/result[2] XPath ifadesi her zaman ikinci sonucu döndürür.
| İfade Türü | |
|---|---|
| Root düğüm | XPath İfadesi: "
/"Seçim:
<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>
|
| Mutlak Yol | XPath İfadesi: "
/WebServiceResponse/result"Seçim:
<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>
|
| Joker karakter içeren yol | XPath İfadesi: "
/WebServiceResponse//location"Seçim:
<location>
<lat>37.4217550</lat>
<lng>-122.0846330</lng>
</location>
|
| Koşullu Yol | XPath İfadesi: "
/WebServiceResponse/result[2]/message"Seçim:
<message>The secret message</message>
|
İlk result öğesinin tüm doğrudan alt öğeleri |
XPath İfadesi: "
/WebServiceResponse/result[1]/*"Seçim:
<type>sample</type>
<name>Sample XML</name>
<location>
<lat>37.4217550</lat>
<lng>-122.0846330</lng>
</location>
|
type metni "örnek" olan bir result öğesinin name. |
XPath İfadesi: "
/WebServiceResponse/result[type/text()='sample']/name"Seçim:
Sample XML
|
Öğeleri seçerken yalnızca bu nesnelerdeki metni değil, düğümleri de seçtiğinizi unutmayın. Genellikle, eşleşen tüm düğümleri yinelemek ve metni ayıklamak istersiniz. Ayrıca metin düğümlerini doğrudan da eşleştirebilirsiniz. Aşağıdaki Metin Düğümleri bölümüne bakın.
XPath'in özellik düğümlerini de desteklediğini ancak tüm Google Haritalar web hizmetlerinin öğeleri özellikler olmadan sunduğunu, bu nedenle özelliklerin eşleştirilmesinin gerekli olmadığını unutmayın.
İfadelerde Metin Seçimi
Bir XML belgesindeki metin, XPath ifadelerinde metin düğümü operatörü aracılığıyla belirtilir. Bu operatör "text()", belirtilen düğümden metin çıkarıldığını gösterir. Örneğin, "//formatted_address/text()" XPath ifadesi, <formatted_address> öğelerindeki tüm metinleri döndürür.
| İfade Türü | |
|---|---|
| Tüm metin düğümleri (boşluk dahil) | XPath İfadesi: "
//text()"Seçim:
sample
Sample XML
37.4217550
-122.0846330
The secret message
|
| Metin Seçimi | XPath İfadesi: "
/WebServiceRequest/result[2]/message/text()"Seçim:
The secret message
|
| Bağlama Duyarlı Seçim | XPath İfadesi: "
/WebServiceRequest/result[type/text() = 'sample']/name/text()"Seçim:
Sample XML
|
Alternatif olarak, bir ifadeyi değerlendirip bir düğüm grubu döndürebilir ve ardından bu "düğüm grubu" üzerinde yineleme yaparak her düğümden metni çıkarabilirsiniz. Aşağıdaki örnekte bu yaklaşımı kullanıyoruz.
XPath hakkında daha fazla bilgi için XPath W3C Spesifikasyonu'na bakın.
Java'da XPath'i değerlendirme
Java, XML'yi ayrıştırma ve javax.xml.xpath.* paketi içinde XPath ifadelerini kullanma konusunda geniş bir destek sunar.
Bu nedenle, bu bölümdeki örnek kodda XML'nin nasıl işleneceğini ve XML hizmeti yanıtlarından verilerin nasıl ayrıştırılacağını göstermek için Java kullanılır.
Java kodunuzda XPath'i kullanmak için önce XPathFactory sınıfının bir örneğini oluşturmanız ve XPath
nesnesi oluşturmak için bu fabrikada newXPath() yöntemini çağırmanız gerekir. Bu nesne daha sonra evaluate() yöntemini kullanarak iletilen XML ve XPath ifadelerini işleyebilir.
XPath ifadelerini değerlendirirken döndürülebilecek olası "düğüm kümelerini" yinelediğinizden emin olun. Bu sonuçlar Java kodunda DOM düğümleri olarak döndürüldüğünden, bu tür birden çok değeri bir NodeList nesnesinde yakalamanız ve bu nesneyi yineleyerek bu düğümlerden metin veya değer çıkarmanız gerekir.
Aşağıdaki kod, XPath nesnesinin nasıl oluşturulacağını, bu nesneye XML ve XPath ifadesinin nasıl atanacağını ve ilgili içeriği yazdırmak için ifadenin nasıl değerlendirileceğini gösterir.
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"); } } }