Prueba la próxima generación de funciones de Directions con la API de Routes, que ahora está disponible en la vista previa.

Prácticas recomendadas para usar los servicios web de la API de Directions

Organiza tus páginas con colecciones Guarda y categoriza el contenido según tus preferencias.

Los servicios web de Google Maps Platform son un conjunto de interfaces HTTP para los servicios de Google que proporcionan datos geográficos a tus aplicaciones de mapas.

En esta guía, se describen algunas prácticas comunes útiles para configurar las solicitudes de servicio web y procesar las respuestas del servicio. Consulta la guía para desarrolladores a fin de obtener la documentación completa de la API de Directions.

¿Qué es un servicio web?

Los servicios web de Google Maps Platform son una interfaz para solicitar datos de la API de Google Maps a servicios externos y usarlos dentro de tus aplicaciones de Maps. Estos servicios se diseñaron para usarse junto con un mapa, de acuerdo con las restricciones de licencia en las Condiciones del Servicio de Google Maps Platform.

Los servicios web de las API de Google Maps usan solicitudes HTTP(S) a URL específicas y pasan parámetros de URL o datos POST en formato JSON como argumentos a los servicios. Por lo general, estos servicios muestran datos en la solicitud HTTP(S) como JSON o XML para que tu aplicación los analice o procese.

Por lo general, una solicitud típica a la API de Directions tiene el siguiente formato:

https://maps.googleapis.com/maps/api/directions/output?parameters

donde output indica el formato de respuesta (por lo general, json o xml).

Nota: Todas las aplicaciones de la API de Directions requieren autenticación. Obtén más información sobre las credenciales de autenticación.

Acceso SSL/TLS

HTTPS es obligatorio para todas las solicitudes de Google Maps Platform que usan claves de API o contienen datos del usuario. Es posible que se rechacen las solicitudes realizadas mediante HTTP que contengan datos sensibles.

Cómo crear una URL válida

Quizás pienses que una URL "válida" es evidente, pero no siempre es así. Una URL que se ingresa en una barra de direcciones de un navegador, por ejemplo, puede contener caracteres especiales (como "上海+中國"); el navegador debe traducir internamente esos caracteres a una codificación diferente antes de la transmisión. Con el mismo token, cualquier código que genere o acepte entradas en UTF-8 podría procesar las URL con caracteres UTF-8 como "válidas", pero también necesitaría traducir esos caracteres antes de enviarlos a un servidor web. Este proceso se llama codificación de URL o codificación porciento.

Caracteres especiales

Necesitamos traducir los caracteres especiales porque todas las URL deben cumplir con la sintaxis que se indica en la especificación del identificador uniforme de recursos (URI). Esto significa que las URL solo deben contener un subconjunto especial de caracteres ASCII: los símbolos alfanuméricos conocidos y algunos caracteres reservados para usar como caracteres de control dentro de las URL. Dichos caracteres se resumen en la siguiente tabla:

Resumen de caracteres válidos para URL
Conjunto deCaracteresUso de URL
Alfanuméricos 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 M N N P P R S T U V W X Y Z 0 1 2 3 4 5 6 7 6 7 Strings de texto, uso de esquemas (http), puerto (8080), etcétera
No reservados - _ . ~ Strings de texto
Reservados ! * ' ( ) ; : @ & = + $ , / ? % # [ ] Caracteres de control o strings de texto

Cuando compiles una URL válida, debes asegurarte de que solo contenga los caracteres que se muestran en la tabla Resumen de caracteres válidos para URL. Adaptar una URL para usar este conjunto de caracteres generalmente provoca dos problemas, de omisión y sustitución:

  • Es posible que quieras usar caracteres que no se encuentren dentro del conjunto anterior. Por ejemplo, los caracteres en otros idiomas, como 上海+中國, se deben codificar mediante los caracteres anteriores. Por convención popular, los espacios (que no se permiten en las URL) suelen representarse con el carácter de signo más '+' también.
  • Hay caracteres dentro del conjunto anterior que son reservados, pero se deben usar literalmente. Por ejemplo, ? se usa en las URL para indicar el comienzo de la cadena de consulta; si deseas usar la string "? and the Mysterions", debes codificar el carácter '?'.

Todos los caracteres que utilicen la codificación de URL se codifican con un carácter '%' y un valor hexadecimal de dos caracteres correspondiente a su carácter UTF-8. Por ejemplo, 上海+中國 en UTF-8 utilizaría la codificación de URL %E4%B8%8A%E6%B5%B7%2B%E4%B8%AD%E5%9C%8B. A su vez, la string ? and the Mysterians utilizaría las codificaciones de URL %3F+and+the+Mysterians o %3F%20and%20the%20Mysterians.

Caracteres comunes que necesitan codificación

A continuación, se indican algunos de los caracteres comunes que se deben codificar:

Carácter no seguro Valor codificado
Barra espaciadora %20
" %22
< %3C
> %3E
# %23
% %25
| %7C

A veces, convertir una URL que recibes a través de la entrada de un usuario puede ser engañoso. Por ejemplo, un usuario puede ingresar una dirección como "5th&Main St.". Por lo general, deberías crear tu URL a partir de sus partes y tratar las entradas de los usuarios como caracteres literales.

Además, las URL tienen un límite de 8,192 caracteres para todos los servicios web de Google Maps Platform y las API web estáticas. Para la mayoría de los servicios, este límite de caracteres se alcanza con poca frecuencia. No obstante, ten en cuenta que algunos servicios tienen varios parámetros que podrían generar URL extensas.

Uso normal de las API de Google

Los clientes de API mal diseñados pueden colocar más carga de la necesaria en Internet y en los servidores de Google. En esta sección se explican algunas de las prácticas recomendadas para los clientes de las API. Seguir estas prácticas recomendadas puede ayudarte a evitar que se bloquee tu aplicación por abuso involuntario de las API.

Interrupción exponencial

En raras ocasiones, puede producirse un error en la entrega de tu solicitud; es posible que recibas un código de respuesta HTTP 4XX o 5XX, o que la conexión TCP simplemente falle en algún lugar entre tu cliente y el servidor de Google. A menudo, vale la pena reintentar la solicitud, ya que la solicitud de seguimiento puede tener éxito cuando falla la original. Sin embargo, es importante no repetir varias veces las solicitudes a los servidores de Google. Este comportamiento repetitivo puede sobrecargar la red entre tu cliente y Google, lo que puede causar problemas para muchas partes.

Un mejor enfoque consiste en realizar nuevos intentos con demoras más prolongadas entre uno y otro. Por lo general, el retraso aumenta por un factor multiplicativo con cada intento, un enfoque conocido como retirada exponencial.

Por ejemplo, considera una aplicación que desea realizar esta solicitud a la API de Time Zone:

https://maps.googleapis.com/maps/api/timezone/json?location=39.6034810,-119.6822510&timestamp=1331161200&key=YOUR_API_KEY

En el siguiente ejemplo de Python se muestra la manera de realizar la solicitud con interrupción 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}")

También debes tener cuidado de que no haya un código de reintento más alto en la cadena de llamadas de la aplicación que lleve a solicitudes repetidas en una sucesión rápida.

Solicitudes sincronizadas

Una gran cantidad de solicitudes sincronizadas a las API de Google puede parecer un ataque de denegación de servicio distribuido (DSD) en la infraestructura de Google y se puede tratar de forma adecuada. Para evitar esto, debes asegurarte de que las solicitudes a la API no se sincronicen entre clientes.

Por ejemplo, considera una aplicación que muestre la hora en la zona horaria actual. Es probable que esta aplicación configure una alarma en el sistema operativo del cliente para que se active al inicio del minuto, de modo que se pueda actualizar la hora que se muestra. La aplicación no debe realizar llamadas a la API como parte del procesamiento asociado con esa alarma.

Realizar llamadas a la API en respuesta a una alarma fija es mala, ya que hace que las llamadas a la API se sincronicen al inicio del minuto, incluso entre diferentes dispositivos, en lugar de distribuirse de manera uniforme con el tiempo. Una aplicación mal diseñada que haga esto producirá un pico de tráfico sesenta veces más normal al comienzo de cada minuto.

En su lugar, un posible buen diseño es tener una segunda alarma configurada en una hora elegida al azar. Cuando se activa esta segunda alarma, la aplicación llama a cualquier API que necesite y almacena los resultados. Cuando la aplicación quiere actualizar su pantalla al comienzo del minuto, usa los resultados almacenados previamente en lugar de volver a llamar a la API. Con este enfoque, las llamadas a la API se distribuyen de manera uniforme. Además, las llamadas a la API no demoran la representación cuando se actualiza la pantalla.

Además de la hora de inicio del minuto, otros tiempos de sincronización comunes deben tener cuidado de no orientar los anuncios al comienzo de la hora y al comienzo de cada día a la medianoche.

Procesamiento de respuestas

En esta sección se discute cómo extraer esos valores de forma dinámica de las respuestas de los servicios web.

Los servicios web de Google Maps proporcionan respuestas fáciles de entender, pero no son fáciles de usar. Cuando realizas una consulta, en lugar de mostrar un conjunto de datos, es probable que quieras extraer algunos valores específicos. En general, se recomienda analizar las respuestas del servicio web y extraer solo los valores que te interesan.

El esquema de análisis que usas depende de si deseas mostrar un resultado en XML o JSON. Las respuestas JSON, que ya son en forma de objetos de JavaScript, se pueden procesar dentro de JavaScript en el cliente. Las respuestas XML se deben procesar mediante un procesador XML y un lenguaje de consulta XML para abordar los elementos dentro del formato XML. En los siguientes ejemplos, usamos XPath, ya que suele admitirse en las bibliotecas de procesamiento XML.

Procesamiento de XML con XPath

XML es un formato de información estructurada relativamente maduro que se usa para el intercambio de datos. Aunque no es tan liviano como JSON, XML ofrece más compatibilidad de lenguajes y herramientas más sólidas. Por ejemplo, el código para procesar XML en Java está integrado en los paquetes javax.xml.

Cuando procesas respuestas XML, debes usar un lenguaje de consulta apropiado para seleccionar nodos dentro del documento XML, en lugar de asumir que los elementos residen en posiciones absolutas dentro del lenguaje de marcado XML. XPath es una sintaxis de lenguaje para describir nodos y elementos de forma única dentro de un documento XML. Las expresiones XPath te permiten identificar contenido específico dentro del documento de respuesta XML.

Expresiones XPath

Estar familiarizado con XPath contribuye en gran medida al desarrollo de un esquema de análisis sólido. Esta sección se centrará en cómo se abordan con XPath los elementos dentro de un documento XML, lo que te permite abordar varios elementos y construir consultas complejas.

XPath usa expresiones para seleccionar elementos dentro de un documento XML con una sintaxis similar a la que se usa para las rutas de directorios. Estas expresiones identifican elementos en un árbol de documentos XML, que es un árbol jerárquico similar al de un DOM. En general, las expresiones XPath son codiciosas, lo que indica que coincidirán con todos los nodos que coincidan con los criterios proporcionados.

Usaremos el siguiente XML abstracto para ilustrar nuestros ejemplos:

<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>

Selección de nodos en expresiones

Las selecciones de XPath seleccionan nodos. El nodo raíz abarca todo el documento. Selecciona este nodo mediante la expresión especial /. Ten en cuenta que el nodo raíz no es el nodo de nivel superior de tu documento XML; en realidad, reside un nivel por encima de este elemento de nivel superior y lo incluye.

Los nodos de los elementos representan los diversos elementos dentro del árbol de documentos XML. Un elemento <WebServiceResponse>, por ejemplo, representa el elemento de nivel superior mostrado en nuestro servicio de muestra anterior. Puedes seleccionar nodos individuales a través de rutas de acceso absolutas o relativas, que se indican por la presencia o ausencia de un carácter "/".

  • Ruta de acceso absoluta: la expresión "/WebServiceResponse/result&; selecciona todos los nodos <result> que son secundarios del nodo <WebServiceResponse>. (Ten en cuenta que ambos elementos descienden del nodo raíz “/”).
  • Ruta relativa del contexto actual: la expresión "result" coincidiría con cualquier elemento <result> dentro del contexto actual. En general, no debes preocuparte por el contexto, ya que sueles procesar resultados de servicios web a través de una sola expresión.

Cualquiera de estas expresiones se puede aumentar mediante la adición de una ruta de acceso con comodín, que se indica con dos barras diagonales (//). Este comodín indica que cero o más elementos pueden coincidir en la ruta de acceso que interviene. Por ejemplo, la expresión XPath //formatted_address, coincidirá con todos los nodos de ese nombre en el documento actual. La expresión //viewport//lat coincidiría con todos los elementos <lat> que pueden rastrear <viewport> como elemento superior.

De forma predeterminada, las expresiones Xpath coinciden con todos los elementos. Puedes restringir la expresión para que coincida con un elemento determinado si proporcionas un predicado, que está entre corchetes ([]). La expresión XPath &/GeocodeResponse/result[2] siempre muestra el segundo resultado, por ejemplo.

Tipo de expresión
Nodo raíz
Expresión de XPath:  "/"
Selección:
    <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>
    
Ruta de acceso absoluta
Expresión de XPath:  "/WebServiceResponse/result"
Selección:
    <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>
    
Ruta de acceso con comodín
Expresión de XPath:  "/WebServiceResponse//location"
Selección:
    <location>
     <lat>37.4217550</lat>
     <lng>-122.0846330</lng>
    </location>
    
Ruta de acceso con predicado
Expresión de XPath: "/WebServiceResponse/result[2]/message"
Selección:
    <message>The secret message</message>
    
Todos los hijos secundarios directos de los primeros result
Expresión de XPath:  "/WebServiceResponse/result[1]/*"
Selección:
     <type>sample</type>
     <name>Sample XML</name>
     <location>
      <lat>37.4217550</lat>
      <lng>-122.0846330</lng>
     </location>
    
El name de un result cuyo texto type es &sample;
Expresión de XPath: "/WebServiceResponse/result[type/text()='sample']/name"
Selección:
    Sample XML
    

Es importante tener en cuenta que, cuando seleccionas elementos, seleccionas nodos, no solo el texto dentro de esos objetos. En general, es recomendable iterar en todos los nodos coincidentes y extraer el texto. También puedes hacer coincidir nodos de texto directamente; consulta Nodos de texto a continuación.

Ten en cuenta que XPath también admite nodos de atributos; sin embargo, todos los servicios web de Google Maps entregan elementos sin atributos, por lo que no es necesario hacer coincidir los atributos.

Selección de texto en expresiones

El texto de un documento XML se especifica en expresiones XPath a través de un operador de nodo de texto. Este operador text() indica la extracción de texto del nodo indicado. Por ejemplo, la expresión de XPath &//formatted_address/text(); mostrará todo el texto dentro de los elementos <formatted_address>.

Tipo de expresión
Todos los nodos de tecto (incluidos espacios en blanco)
Expresión de XPath: "//text()"
Selección:
    sample
    Sample XML

    37.4217550
    -122.0846330
    The secret message
    
Selección de texto
Expresión de XPath:  "/WebServiceRequest/result[2]/message/text()"
Selección:
    The secret message
    
Selección dependiente del contexto
Expresión de XPath:  "/WebServiceRequest/result[type/text() = 'sample']/name/text()"
Selección:
    Sample XML
    

Como alternativa, puedes evaluar una expresión y mostrar un conjunto de nodos y, luego, iterar sobre ese conjunto de nodos mediante la extracción del texto de cada nodo. En el siguiente ejemplo usamos este enfoque.

Para obtener más información sobre XPath, consulta la Especificación W3C de XPath W3C.

Evaluar XPath en Java

Java tiene una amplia compatibilidad para analizar XML y usar expresiones XPath dentro del paquete javax.xml.xpath.*. Por ese motivo, el código de muestra en esta sección usa Java para ilustrar cómo manejar XML y analizar datos de respuestas de servicios XML.

Para usar XPath en tu código Java, primero deberás crear una instancia de XPathFactory y llamar a newXPath() en esa fábrica para crear un objeto XPath . Este objeto puede procesar expresiones XML y XPath que se pasan mediante el método evaluate().

Cuando evalúes expresiones XPath, asegúrate de iterar sobre los posibles conjuntos de nodos que se pueden mostrar. Debido a que estos resultados se muestran como nodos DOM en código Java, debes capturar esos valores múltiples dentro de un objeto NodeList y, luego, iterar sobre ese objeto para extraer el texto o los valores de esos nodos.

En el siguiente código, se ilustra cómo crear un objeto XPath, asignarle XML y una expresión XPath, y evaluar la expresión para imprimir el contenido 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");
    }
  }
}