Les services Web Google Maps Platform sont un ensemble d'interfaces HTTP vers les services Google fournissant des données géographiques pour vos applications de cartographie.
Ce guide décrit certaines pratiques courantes utiles pour configurer les requêtes de service Web et traiter les réponses du service. Reportez-vous au guide du développeur pour obtenir la documentation complète de l'API Directions.
Qu'est-ce qu'un service Web ?
Les services Web Google Maps Platform permettent de demander des données de l'API Google Maps à des services externes et d'utiliser les données dans vos applications Maps. Ces services sont conçus pour être utilisés avec une carte, conformément aux Restrictions de licence des conditions d'utilisation de Google Maps Platform.
Les services Web des API Google Maps utilisent des requêtes HTTP(S) à des URL spécifiques, en transmettant des paramètres d'URL et/ou des données POST au format JSON en tant qu'arguments aux services. En général, ces services renvoient des données dans le corps de la réponse au format JSON ou XML à des fins d'analyse et/ou de traitement par votre application.
Une requête d'API Directions typique se présente généralement sous la forme suivante:
https://maps.googleapis.com/maps/api/directions/output?parameters
où output
indique le format de réponse (généralement json
ou xml
).
Remarque: Toutes les applications de l'API Directions nécessitent une authentification. Obtenez plus d'informations sur les identifiants d'authentification.
Accès SSL/TLS
HTTPS est requis pour toutes les requêtes Google Maps Platform qui utilisent des clés API ou contiennent des données utilisateur. Les requêtes effectuées sur HTTP qui contiennent des données sensibles peuvent être refusées.
Créer une URL valide
Vous pensez peut-être qu'une URL "valide" va de soi, mais ce n'est pas toujours le cas. Une URL saisie dans une barre d'adresse d'un navigateur, par exemple, peut contenir des caractères spéciaux (comme "上海+中國"
). Le navigateur doit alors convertir en interne ces caractères en un autre code avant de les transmettre.
De même, tout code qui génère ou accepte le format d'entrée UTF-8 peut considérer comme "valides" les URL contenant des caractères UTF-8, mais il doit convertir ces caractères avant de les envoyer à un serveur Web.
Ce processus est appelé encodage d'URL ou encodage-pourcent.
Caractères spéciaux
Nous devons convertir les caractères spéciaux, car toutes les URL doivent respecter la syntaxe de la spécification Uniform Resource Identifier (URI). En fait, les URL doivent contenir un sous-ensemble spécifique de caractères ASCII (symboles alphanumériques courants), ainsi que des caractères réservés et utilisés comme caractères de commande dans les URL. Le tableau ci-dessous récapitule ces caractères :
Ensemble | Caractères | Utilisation de l'URL |
---|---|---|
Alphanumériques | a b f g h 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 J J L M M N N P P R R T U V W X Y Z 0 1 2 3 4 5 6 7 9 9 | Chaînes de texte, utilisation du schéma (http ), port (8080 ), etc. |
Non réservés | - _ . ~ | Chaînes de texte |
Réservés | ! * ' ( ) ; : @ & = + $ , / ? % # [ ] | Caractères de commande et/ou chaînes de texte |
Lorsque vous créez une URL valide, vous devez vous assurer qu'elle ne contient que des caractères affichés dans le tableau "Récapitulatif des caractères d'URL valides". Vérifier qu'une URL utilise ce jeu de caractères permet généralement d'identifier deux problèmes (une omission et un remplacement) :
- Les caractères que vous souhaitez utiliser ne figurent pas dans le tableau ci-dessus. Par exemple, les caractères de certaines langues étrangères (
上海+中國
, par exemple) doivent être encodés à l'aide des caractères ci-dessus. Selon une pratique courante, les espaces (qui ne sont pas autorisés dans les URL) sont également souvent représentés par le caractère'+'
. - Des caractères figurent dans le tableau ci-dessus comme des caractères réservés, mais doivent être utilisés littéralement.
Par exemple,
?
est utilisé dans les URL pour indiquer le début de la chaîne de requête. Si vous souhaitez utiliser la chaîne "? et les Mysterions", vous devez encoder le caractère'?'
.
Tous les caractères à encoder en URL le sont à l'aide du caractère '%'
et d'une valeur hexadécimale à deux caractères correspondant à leur équivalent UTF-8. Par exemple, 上海+中國
au format UTF-8 serait encodé en URL sous la forme %E4%B8%8A%E6%B5%B7%2B%E4%B8%AD%E5%9C%8B
. La chaîne ? and the Mysterians
serait encodée en URL sous la forme %3F+and+the+Mysterians
ou %3F%20and%20the%20Mysterians
.
Caractères courants qui doivent être encodés
Voici quelques caractères courants à encoder :
Caractère non fiable | Valeur encodée |
---|---|
Espace | %20 |
" | %22 |
< | %3C |
> | %3E |
# | %23 |
% | %25 |
| | %7C |
Convertir une URL envoyée par un utilisateur peut être difficile. Par exemple, un utilisateur peut saisir une adresse sous la forme "5&rue Longue". Généralement, vous devez créer votre URL à partir des éléments de cette adresse saisie, en traitant chaque entrée utilisateur comme des caractères littéraux.
En outre, les URL sont limitées à 8 192 caractères pour tous les services Web Google Maps Platform et les API Web statiques. Pour la plupart des services, cette limite de caractères est rarement atteinte. Notez toutefois que certains services incluent plusieurs paramètres pouvant accroître la longueur des URL.
Bon usage des Google API
Les clients d'API de mauvaise conception peuvent placer plus de charge que nécessaire sur Internet et les serveurs de Google. Cette section contient les bonnes pratiques pour les clients de ces API. En suivant ces bonnes pratiques, vous pouvez éviter que votre application soit bloquée en raison d'une utilisation abusive des API.
Retrait exponentiel
Dans de rares cas, un problème peut survenir lors de la diffusion de votre requête. Vous pouvez recevoir un code de réponse HTTP 4XX ou 5XX, ou la connexion TCP peut tout simplement échouer entre votre client et le serveur de Google. Il est souvent utile de relancer la requête, car la requête de suivi peut aboutir lorsque l'original a échoué. Toutefois, il est important de ne pas simplement effectuer des requêtes en boucle à des serveurs Google. Ce comportement en boucle peut surcharger le réseau entre votre client et Google, ce qui entraîne des problèmes pour de nombreuses parties.
Il est préférable de réessayer en allongeant progressivement les délais entre deux tentatives. Généralement, le retard est augmenté par un facteur multiplicatif à chaque tentative, une approche appelée intervalle exponentiel entre les tentatives.
Prenons l'exemple d'une application qui souhaite envoyer cette requête à l'API Time Zone:
https://maps.googleapis.com/maps/api/timezone/json?location=39.6034810,-119.6822510×tamp=1331161200&key=YOUR_API_KEY
L'exemple Python suivant illustre comment effectuer la requête avec le retrait exponentiel :
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}")
Vous devez également veiller à ce qu'aucune nouvelle tentative de code ne se trouve plus haut dans la chaîne d'appel d'application, ce qui entraîne des requêtes répétées successives.
Requêtes synchronisées
Un grand nombre de requêtes synchronisées vers les API de Google peuvent ressembler à une attaque de déni de service distribué (DDoS) sur l'infrastructure de Google et être traitées en conséquence. Pour éviter cela, assurez-vous que les requêtes API ne sont pas synchronisées entre les clients.
Prenons l'exemple d'une application qui affiche l'heure dans le fuseau horaire actuel. Cette application définira probablement une alarme dans le système d'exploitation client pour la réveiller au début de la minute, afin que l'heure affichée puisse être mise à jour. L'application ne doit pas effectuer d'appels d'API dans le cadre du traitement associé à l'alarme.
Les appels d'API en réponse à une alarme fixe sont déconseillés, car ils sont synchronisés au début de la minute, même entre différents appareils, au lieu d'être distribués uniformément au fil du temps. Une application mal conçue, ce qui générera un pic de trafic à 60 fois le niveau normal au début de chaque minute.
Il est recommandé d'avoir une seconde alerte définie sur une heure choisie de manière aléatoire. Lorsque cette deuxième alarme se déclenche, l'application appelle les API dont elle a besoin et stocke les résultats. Lorsque l'application souhaite mettre à jour son affichage au début de la minute, elle utilise les résultats précédemment stockés au lieu d'appeler à nouveau l'API. Avec cette approche, les appels d'API sont répartis uniformément dans le temps. De plus, les appels d'API ne retardent pas le rendu lorsque l'affichage est en cours de mise à jour.
Hormis le début de la minute, les autres heures de synchronisation courantes que vous devez ne pas cibler sont celles du début d'une heure et du début de chaque jour à minuit.
Traitement des réponses
Cette section explique comment extraire ces valeurs de manière dynamique à partir des réponses d'un service Web.
Les services Web Google Maps fournissent des réponses faciles à comprendre, mais qui ne sont pas exactement conviviales. Lorsque vous exécutez une requête, plutôt que d'afficher un ensemble de données, vous aurez probablement besoin d'extraire quelques valeurs spécifiques. En règle générale, vous souhaitez analyser les réponses du service Web et extraire uniquement les valeurs qui vous intéressent.
Le schéma d'analyse que vous utilisez varie selon que vous renvoyez le résultat au format XML ou JSON. Les réponses JSON, déjà présentes sous forme d'objets JavaScript, peuvent être traitées dans JavaScript lui-même sur le client. Les réponses XML doivent être traitées à l'aide d'un processeur XML et d'un langage de requête XML pour traiter les éléments au format XML. Nous utilisons XPath dans les exemples suivants, car il est couramment compatible avec les bibliothèques de traitement XML.
Traitement XML avec XPath
XML est un format d'informations structurées relativement mature utilisé pour l'échange de données. Bien qu'il ne soit pas aussi léger que JSON, le format XML fournit une meilleure compatibilité avec les langages et des outils plus robustes. Le code utilisé pour le traitement XML en Java, par exemple, est intégré aux packages javax.xml
.
Lors du traitement des réponses XML, vous devez utiliser un langage de requête approprié pour sélectionner des nœuds dans le document XML, au lieu de supposer que les éléments se trouvent à des positions absolues dans le balisage XML. XPath est une syntaxe de langage permettant de décrire de manière unique les nœuds et les éléments d'un document XML. Les expressions XPath vous permettent d'identifier un contenu spécifique dans le document de réponse XML.
Expressions XPath
Une certaine connaissance de XPath permet d'élaborer un schéma d'analyse robuste. Cette section porte sur la façon dont les éléments d'un document XML sont traités avec XPath, ce qui vous permet de traiter plusieurs éléments et de créer des requêtes complexes.
XPath utilise des expressions pour sélectionner des éléments dans un document XML, à l'aide d'une syntaxe semblable à celle utilisée pour les chemins d'accès aux répertoires. Ces expressions identifient les éléments d'une arborescence de documents XML, qui est une arborescence hiérarchique semblable à celle d'un DOM. En général, les expressions XPath sont gourmandes, ce qui indique qu'elles correspondent à tous les nœuds correspondant aux critères fournis.
Nous allons utiliser le code XML abstrait suivant pour illustrer nos exemples:
<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>
Sélection de nœud dans les expressions
Les sélections XPath permettent de sélectionner des nœuds. Le nœud racine englobe l'ensemble du document. Vous sélectionnez ce nœud à l'aide de l'expression spéciale "/
". Notez que le nœud racine n'est pas le nœud de niveau supérieur de votre document XML. En fait, il se trouve à un niveau au-dessus de cet élément de niveau supérieur et l'inclut.
Les nœuds d'élément représentent les différents éléments de l'arborescence de documents XML. Un élément <WebServiceResponse>
, par exemple, représente l'élément de niveau supérieur renvoyé dans notre exemple de service ci-dessus. Vous sélectionnez les nœuds individuels via des chemins absolus ou relatifs, indiqués par la présence ou l'absence d'un caractère "/
" au début.
- Chemin absolu: l'expression "
/WebServiceResponse/result
" sélectionne tous les nœuds<result>
qui sont des enfants du nœud<WebServiceResponse>
. Notez que ces deux éléments descendent du nœud racine "/
". - Chemin relatif du contexte actuel: l'expression "
result
" correspond à tous les éléments<result>
du contexte actuel. En règle générale, vous n'avez pas à vous soucier du contexte, car vous traitez les résultats des services Web via une seule expression.
L'une ou l'autre de ces expressions peut être complétée par l'ajout d'un chemin générique, indiqué par une double barre oblique ("//
"). Ce caractère générique indique qu'aucun ou plusieurs éléments peuvent correspondre dans le chemin intermédiaire. L'expression XPath "//formatted_address
", par exemple, correspond à tous les nœuds de ce nom dans le document actuel.
L'expression //viewport//lat
correspond à tous les éléments <lat>
pouvant tracer <viewport>
en tant que parent.
Par défaut, les expressions XPath renvoient tous les éléments. Vous pouvez limiter l'expression à correspondre à un élément donné en fournissant un prédicat, entouré de crochets ([]
). L'expression XPath "/GeocodeResponse/result[2]
" renvoie toujours le deuxième résultat, par exemple.
Type d'expression | |
---|---|
Nœud racine | Expression XPath : "
/ "Sélection:
<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> |
Chemin absolu | Expression XPath : "
/WebServiceResponse/result "Sélection:
<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> |
Chemin avec générique | Expression XPath : "
/WebServiceResponse//location "Sélection:
<location> <lat>37.4217550</lat> <lng>-122.0846330</lng> </location> |
Chemin avec prédicat | Expression XPath : "
/WebServiceResponse/result[2]/message "Sélection:
<message>The secret message</message> |
Tous les enfants directs de la result |
Expression XPath : "
/WebServiceResponse/result[1]/* "Sélection:
<type>sample</type> <name>Sample XML</name> <location> <lat>37.4217550</lat> <lng>-122.0846330</lng> </location> |
name d'un result dont le texte type est "sample". |
Expression XPath : "
/WebServiceResponse/result[type/text()='sample']/name "Sélection:
Sample XML |
Il est important de noter que lorsque vous sélectionnez des éléments, vous sélectionnez des nœuds et pas seulement le texte dans ces objets. En règle générale, vous devez itérer tous les nœuds correspondants et extraire le texte. Vous pouvez également mettre en correspondance directement les nœuds de texte. Consultez la section Nœuds de texte ci-dessous.
Notez que XPath est également compatible avec les nœuds d'attributs. Toutefois, tous les services Web Google Maps utilisent des éléments sans attributs. Il n'est donc pas nécessaire de faire correspondre les attributs.
Sélection de texte dans les expressions
Le texte d'un document XML est spécifié dans les expressions XPath via un opérateur text node. L'opérateur "text()
" indique l'extraction de texte à partir du nœud indiqué. Par exemple, l'expression XPath "//formatted_address/text()
" renvoie l'intégralité du texte contenu dans les éléments <formatted_address>
.
Type d'expression | |
---|---|
Tous les nœuds de texte (y compris les espaces vides) | Expression XPath : "
//text() "Sélection:
sample Sample XML 37.4217550 -122.0846330 The secret message |
Sélection de texte | Expression XPath : "
/WebServiceRequest/result[2]/message/text() "Sélection:
The secret message |
Sélection en fonction du contexte | Expression XPath : "
/WebServiceRequest/result[type/text() = 'sample']/name/text() "Sélection:
Sample XML |
Vous pouvez également évaluer une expression et renvoyer un ensemble de nœuds, puis itérer cet "ensemble de nœuds" en extrayant le texte de chaque nœud. Cette approche est utilisée dans l'exemple ci-dessous.
Pour en savoir plus sur XPath, consultez la spécification XPath W3C.
Évaluer XPath en Java
Java est largement compatible avec l'analyse de fichiers XML et l'utilisation d'expressions XPath dans le package javax.xml.xpath.*
.
C'est pourquoi l'exemple de code de cette section utilise Java pour montrer comment gérer XML et analyser les données des réponses du service XML.
Pour utiliser XPath dans votre code Java, vous devez d'abord instancier une instance de XPathFactory
et appeler newXPath()
sur cette fabrique pour créer un objet XPath
. Cet objet peut ensuite traiter les expressions XML et XPath transmises à l'aide de la méthode evaluate()
.
Lorsque vous évaluez des expressions XPath, assurez-vous d'effectuer une itération sur les éventuels "ensembles de nœuds" susceptibles d'être renvoyés. Étant donné que ces résultats sont renvoyés en tant que nœuds DOM dans le code Java, vous devez capturer ces valeurs multiples dans un objet NodeList
et itérer cet objet pour extraire du texte ou des valeurs de ces nœuds.
Le code suivant montre comment créer un objet XPath
, l'attribuer au format XML et à une expression XPath, et évaluer l'expression pour imprimer le contenu correspondant.
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"); } } }