Os serviços da Web da Plataforma Google Maps são um conjunto de interfaces HTTP para serviços do Google que fornecem dados geográficos para seus aplicativos de mapas.
Neste guia, descrevemos algumas práticas comuns que são úteis para configurar suas solicitações de serviço e processamento de Web. Consulte o guia do desenvolvedor para ver a documentação completa da API Directions.
O que é um serviço Web?
Os serviços da Web da Plataforma Google Maps são uma interface para solicitar dados da API Maps de serviços externos e usar os dados nos seus aplicativos do Maps. Esses serviços foram projetados para serem usados em conjunto com um mapa, de acordo com as Restrições de licença nos Termos de Serviço da Plataforma Google Maps.
Os serviços da Web das APIs Maps usam solicitações HTTP(S) para URLs específicos, transmitindo parâmetros de URL e/ou dados POST no formato JSON como argumentos para os serviços. Geralmente, esses serviços retornam dados na solicitação HTTP(S) como JSON ou XML para análise e/ou processamento pelo aplicativo.
Uma solicitação típica da API Directions costuma ter o seguinte formato:
https://maps.googleapis.com/maps/api/directions/output?parameters
em que output
indica o formato da resposta (geralmente
json
ou xml
).
Observação: todos os apps da API Directions exigem autenticação. Veja mais informações sobre as credenciais de autenticação.
Acesso SSL/TLS
O HTTPS é obrigatório para todas as solicitações da Plataforma Google Maps que usam chaves de API ou contêm dados do usuário. As solicitações feitas por HTTP que contêm dados confidenciais podem ser rejeitadas.
Criar um URL válido
Você pode achar que um URL "válido" é imediatamente identificável, mas não funciona assim. Um URL inserido em uma barra de endereço de um navegador, por exemplo, pode conter caracteres especiais (por exemplo, "上海+中國"
). O navegador precisa converter internamente esses caracteres em uma codificação diferente antes de transmiti-los.
Da mesma forma, qualquer código que gere ou aceite entrada UTF-8 pode tratar URLs com caracteres UTF-8 como "válidos", mas também precisa converter esses caracteres antes de enviá-los a um servidor da Web.
Esse processo é chamado de codificação de URL ou codificação por cento.
Caracteres especiais
É necessário traduzir caracteres especiais porque todos os URLs precisam estar em conformidade com a sintaxe especificada pela especificação do localizador uniforme de recursos (URI, na sigla em inglês). Efetivamente, isso significa que os URLs devem conter apenas um subconjunto especial de caracteres ASCII: os familiares símbolos alfanuméricos e alguns caracteres reservados para uso como caracteres de controle em URLs. Esta tabela resume esses caracteres:
Conjunto | Caracteres | Uso em URLs |
---|---|---|
Alfanuméricos | a b c d e f g h i j k k l m n o p q r s t u v x y z A B C D E F G H I J K L M N N P P R S T U V X Y Z 0 1 2 3 4 5 5 5 | Strings de texto, uso do esquema (http ), porta (8080 ) etc. |
Não reservados | - _ . ~ | Strings de texto |
Reservados | ! * ' ( ) ; : @ & = + $ , / ? % # [ ] | Caracteres de controle e/ou strings de texto |
Ao criar um URL válido, você precisa garantir que ele contenha apenas os caracteres mostrados na tabela Resumo de caracteres de URL válidos. Conformar um URL ao uso desse conjunto de caracteres geralmente causa dois problemas, um de omissão e um de substituição.
- Caracteres que você quer processar existem fora desse conjunto. Por exemplo, os caracteres de idiomas estrangeiros como
上海+中國
precisam ser codificados como mostrado acima. Por convenção popular, os espaços (que não são permitidos nos URLs) também são geralmente representados pelo caractere do sinal de adição ('+'
). - Caracteres existem no conjunto acima como caracteres reservados, mas precisam ser usados literalmente.
Por exemplo,
?
é usado em URLs para indicar o início da string de consulta. Se você quiser usar a string "? and the Mysterions", codifique o caractere'?'
.
Todos os caracteres que precisam ser codificados para serem adicionados a URLs são codificados por meio do uso de um '%'
e um valor hexadecimal de dois caracteres correspondente ao seu caractere UTF-8. Por exemplo, 上海+中國
em UTF-8 seria codificado como %E4%B8%8A%E6%B5%B7%2B%E4%B8%AD%E5%9C%8B
para uso em URLs. A string ? and the Mysterians
seria codificada em um URL como %3F+and+the+Mysterians
ou %3F%20and%20the%20Mysterians
.
Caracteres comuns que precisam de codificação
Alguns caracteres comuns que precisam ser codificados:
Caractere inválido | Valor codificado |
---|---|
Espaço | %20 |
" | %22 |
< | %3C |
> | %3E |
# | %23 |
% | %25 |
| | %7C |
Converter um URL recebido de uma entrada do usuário pode ser complicado. Por exemplo, um usuário pode inserir um endereço como "5th&Main St". Geralmente, você precisa criar o URL das partes dele, tratando quaisquer entradas do usuário como caracteres literais.
Além disso, os URLs estão limitados a 8.192 caracteres para todos os serviços da Web da Plataforma Google Maps e APIs estáticas da Web. Para a maioria dos serviços, esse limite raramente é atingido. No entanto, alguns serviços têm diversos parâmetros que podem resultar em URLs longos.
Uso adequado das Google APIs
Clientes da API mal projetados podem colocar mais carga do que o necessário nos servidores da Internet e do Google. Esta seção contém algumas das melhores práticas para cliente das APIs. Seguir essas práticas recomendadas pode ajudar a evitar que seu aplicativo seja bloqueado por abuso inadvertido das APIs.
Espera exponencial
Em casos raros, algo pode dar errado na sua solicitação. Você pode receber um código de resposta HTTP 4XX ou 5XX, ou a conexão TCP pode simplesmente falhar em algum lugar entre o cliente e o servidor do Google. Muitas vezes vale a pena tentar novamente a solicitação, porque a solicitação de acompanhamento pode ter êxito quando a original falhar. No entanto, é importante não repetir as solicitações repetidamente para os servidores do Google. Esse comportamento de loop pode sobrecarregar a rede entre o cliente e o Google, o que causa problemas para muitas partes.
Uma melhor abordagem é tentar novamente com intervalos maiores entre as tentativas. Normalmente, o atraso é aumentado por um fator multiplicador em cada tentativa, uma abordagem conhecida como espera exponencial.
Por exemplo, considere um aplicativo que quer fazer essa solicitação à API Time Zone:
https://maps.googleapis.com/maps/api/timezone/json?location=39.6034810,-119.6822510×tamp=1331161200&key=YOUR_API_KEY
O exemplo de Python a seguir mostra como fazer a solicitação com retirada exponencial:
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}")
Também é necessário ter cuidado para que não haja um novo código mais alto na cadeia de chamadas do aplicativo que leva a solicitações repetidas em rápida sucessão.
Solicitações sincronizadas
Um grande número de solicitações sincronizadas às APIs do Google pode parecer um ataque de negação de serviço distribuído (DDoS, na sigla em inglês) à infraestrutura do Google e pode ser tratado de acordo com isso. Para evitar isso, verifique se as solicitações de API não estão sincronizadas entre os clientes.
Por exemplo, considere um aplicativo que exibe a hora do fuso horário atual. Este aplicativo provavelmente definirá um alarme no sistema operacional do cliente, despertando-o no início do minuto, para que o horário exibido possa ser atualizado. O aplicativo não pode fazer chamadas de API como parte do processamento associado a esse alarme.
Fazer chamadas de API em resposta a um alarme fixo é ruim, porque resulta em sincronizações das chamadas de API para o início do minuto, mesmo entre diferentes dispositivos, em vez de serem distribuídas uniformemente ao longo do tempo. Um aplicativo mal projetado fazendo isso produzirá um pico de tráfego com 60 vezes mais níveis normais no início de cada minuto.
Em vez disso, um bom possível design é ter um segundo alarme definido a um horário escolhido aleatoriamente. Quando esse segundo alarme dispara, o aplicativo chama todas as APIs necessárias e armazena os resultados. Quando o aplicativo quiser atualizar a tela no início do minuto, ele vai usar os resultados armazenados anteriormente em vez de chamar a API novamente. Com essa abordagem, as chamadas de API são distribuídas uniformemente com o tempo. Além disso, as chamadas de API não atrasam a renderização quando a tela está sendo atualizada.
Além do início do minuto, outros horários comuns de sincronização que você precisa ter cuidado para não segmentar são no início de uma hora e no início de cada dia à meia-noite.
Processar respostas
Esta seção discute como extrair esses valores das respostas dos serviços web de forma dinâmica.
Os serviços da Web do Google Maps fornecem respostas fáceis de entender, mas não exatamente fáceis de usar. Ao executar uma consulta, em vez de exibir um conjunto de dados, é recomendável extrair alguns valores específicos. Geralmente, convém analisar as respostas do serviço da Web e extrair apenas os valores de seu interesse.
O esquema de análise usado depende do retorno de uma saída em XML ou JSON. As respostas JSON, já na forma de objetos JavaScript, podem ser processadas no próprio JavaScript no cliente. As respostas XML precisam ser processadas usando um processador XML e uma linguagem de consulta XML para abordar elementos dentro do formato XML. Usamos o XPath nos exemplos a seguir, porque ele costuma ser compatível com bibliotecas de processamento XML.
Processar XML com XPath
XML é um formato de informações estruturadas relativamente maduro usado para troca de dados. Embora não seja tão leve quanto JSON, o formato XML
oferece mais suporte de linguagem e ferramentas mais robustas. O código para
processar XML em Java, por exemplo, é integrado aos pacotes
javax.xml
.
Ao processar respostas XML, use uma linguagem de consulta apropriada para selecionar nós no documento XML, em vez de presumir que os elementos residem em posições absolutas na marcação XML. O XPath é uma sintaxe de linguagem para descrever exclusivamente nós e elementos em um documento XML. As expressões XPath permitem identificar conteúdo específico no documento de resposta XML.
Expressões XPath
Conhecer bem o XPath ajuda muito a desenvolver um esquema de análise robusto. Esta seção se concentrará em como os elementos em um documento XML são tratados com o XPath, permitindo que você aborde vários elementos e construa consultas complexas.
O XPath usa expressões para selecionar elementos em um documento XML, usando uma sintaxe semelhante àquela usada para caminhos de diretório. Essas expressões identificam elementos em uma árvore de documentos XML, que é uma árvore hierárquica parecida com a de um DOM. Geralmente, as expressões XPath são ácidas, indicando que corresponderão a todos os nós que corresponderem aos critérios fornecidos.
Usaremos o XML abstrato a seguir para ilustrar nossos exemplos:
<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>
Seleção de nós em expressões
As seleções do XPath selecionam nós. O nó raiz
abrange o documento inteiro. Selecione esse nó usando
a expressão especial "/
". O nó
raiz não é o nó de nível superior do seu documento XML. Na verdade,
ele reside um nível acima desse elemento de nível superior e o inclui
.
Os nós do elemento representam os vários elementos da árvore de
documentos XML. Um elemento <WebServiceResponse>
,
por exemplo, representa o elemento de nível superior retornado no nosso
serviço de amostra acima. Você seleciona nós individuais por meio de
caminhos absolutos ou relativos, indicados pela presença ou
ausência de um caractere"quot;/
" inicial".
- Caminho absoluto: a expressão "
/WebServiceResponse/result
" seleciona todos os nós<result>
que são filhos do nó<WebServiceResponse>
. Observe que ambos os elementos descendem do nó raiz "/
". - Caminho relativo do contexto atual: a expressão
"quot;
result
" corresponderia a qualquer elemento<result>
no contexto atual. Geralmente, não é preciso se preocupar com contexto, já que você normalmente processa resultados de serviços da Web com uma única expressão.
Qualquer uma dessas expressões pode ser aumentada com a adição
de um caminho curinga, indicado por uma barra dupla ("//
").
Esse caractere curinga indica que zero ou mais elementos podem corresponder ao
caminho intermediário. A expressão XPath "//formatted_address
,"
por exemplo, corresponderá a todos os nós desse nome no documento atual.
A expressão //viewport//lat
corresponderia a todos
os elementos <lat>
que podem rastrear <viewport>
como pai.
Por padrão, as expressões XPath correspondem a todos os elementos. É possível restringir
a expressão para corresponder a um determinado elemento fornecendo um predicado,
que está entre colchetes ([]
). A expressão XPath
"quot;/GeocodeResponse/result[2]
sempre retorna o
segundo resultado, por exemplo.
Tipo de expressão | |
---|---|
Root node | Expressão XPath: "
/ "Seleção:
<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> |
Caminho absoluto | Expressão XPath: "
/WebServiceResponse/result "Seleção:
<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> |
Caminho com curinga | Expressão XPath: "
/WebServiceResponse//location "Seleção:
<location> <lat>37.4217550</lat> <lng>-122.0846330</lng> </location> |
Caminho com predicado | Expressão XPath: "
/WebServiceResponse/result[2]/message "Seleção:
<message>The secret message</message> |
Todos os filhos diretos do primeiro result |
Expressão XPath: "
/WebServiceResponse/result[1]/* "Seleção:
<type>sample</type> <name>Sample XML</name> <location> <lat>37.4217550</lat> <lng>-122.0846330</lng> </location> |
O name de um result cujo texto type é "sample." |
Expressão XPath: "
/WebServiceResponse/result[type/text()='sample']/name "Seleção:
Sample XML |
É importante observar que, ao selecionar elementos, você seleciona os nós, não apenas o texto dentro desses objetos. Geralmente, convém iterar todos os nós correspondentes e extrair o texto. Você também pode corresponder diretamente aos nós de texto. Consulte Nós de texto abaixo.
O XPath também é compatível com nós de atributos. No entanto, todos os serviços da Web do Google Maps exibem elementos sem atributos, portanto, a correspondência de atributos não é necessária.
Seleção de texto em expressões
O texto em um documento XML é especificado em expressões XPath
por meio de um operador de nó de texto. Este operador "text()
"
indica a extração de texto do nó indicado. Por exemplo,
a expressão XPath "//formatted_address/text()
"
retornará todo o texto nos elementos
<formatted_address>
.
Tipo de expressão | |
---|---|
Todos os nós de texto (incluindo espaços) | Expressão XPath: "
//text() "Seleção:
sample Sample XML 37.4217550 -122.0846330 The secret message |
Seleção de texto | Expressão XPath: "
/WebServiceRequest/result[2]/message/text() "Seleção:
The secret message |
Seleção com reconhecimento de contexto | Expressão XPath: "
/WebServiceRequest/result[type/text() = 'sample']/name/text() "Seleção:
Sample XML |
Como alternativa, você pode avaliar uma expressão e retornar um conjunto de nós e, em seguida, iterar sobre esse "quot;node set"," extraindo o texto de cada nó. Usamos essa abordagem no exemplo abaixo.
Para saber mais sobre o XPath, consulte a especificação XPath W3C.
Como avaliar XPath em Java
O Java tem ampla compatibilidade com a análise de XML e o uso de expressões XPath
no pacote javax.xml.xpath.*
.
Por esse motivo, a amostra de código nesta seção usa Java para
ilustrar como processar XML e analisar dados de respostas de serviços XML.
Para usar o XPath no código Java, primeiro é necessário instanciar
uma instância de um XPathFactory
e chamar
newXPath()
nessa fábrica para criar um objeto XPath
. Esse objeto poderá processar expressões XML
e XPath transmitidas usando o método evaluate()
.
Ao avaliar expressões XPath, lembre-se de iterar
em qualquer "conjuntos de nós" possíveis que possam ser retornados. Como esses
resultados são retornados como nós DOM no código Java, capture
esses diversos valores em um objeto NodeList
e
itere sobre esse objeto para extrair qualquer texto ou valores desses
nós.
O código a seguir ilustra como criar um objeto XPath
,
atribuir um XML e uma expressão XPath a ele e avaliar a
expressão para imprimir o conteúdo relevante.
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"); } } }