Cómo usar la API de Geocoding de Google

Como usar la API de Geocoding de Google

En este artículo se demuestra paso a paso cómo usar la API de Geocoding de Google en un caso de uso muy común, con lo que nos será muy sencillo aplicar esta tecnología a nuestras aplicaciones web. Para seguir el desarrollo de este artículo es necesario que tengas nociones básicas de HTML y de JavaScript.

Qué es la API de Geocoding

La API de Geocoding de Google nos provee de dos servicios fundamentales:

  1. Nos permite convertir direcciones como Calle de la Plata 25, 28021 Madrid en unas coordenadas geográficas de latitud y longitud (40.3487, -3.7056) que podemos usar, por ejemplo, para marcar un punto concreto de un mapa.
  2. El servicio inverso, es decir, dadas unas coordenadas geográficas obtener la dirección de calle, número, … a la que corresponde (Geocoding inverso).

Esta API forma parte de los servicios de Google Cloud (concretamente es una parte de Google Maps Platform) y es bastante sencilla de usar, aunque no es un servicio totalmente gratuito. Si quieres usar esta API en tu proyecto necesitarás dar de alta un proyecto en la Consola de Cloud de Google y crear una clave de API.

El precio de este servicio es de $5 por cada 1000 solicitudes, siendo gratuitas las primeras 40.000 solicitudes del mes(*). Revisa aquí la información detalladas sobre los precios de los servicios de Google Maps.

(*) Los precios de los servicios de Google cambian con frecuencia. La información aportada corresponde al momento de publicación del artículo. Consultar el enlace proporcionado para una información actualizada.

Nuestro caso de uso

En este artículo vamos a demostrar paso a paso el uso de la API de Geocoding para resolver un caso de uso común: Tenemos un formulario en el que debemos rellenar los datos de una dirección postal (calle y número, municipio, provincia y código postal), pero los datos a rellenar se refieren a la posición en la que nos encontramos actualmente.

Formulario tipo para nuestro caso de uso

Para simplificar el uso de nuestra aplicación, lo que queremos es disponer de un botón que rellene los campos del formulario por nosotros usando la posición actual de nuestro móvil.

¡¡Fácil y útil!! ¿No crees?

Pues vamos a ver cómo podemos hacerlo paso a paso.

Paso 1: Nuestro formulario web

Lo primero de todo es crear nuestro formulario web con los campos para la dirección y un botón para que rellene el formulario a partir de nuestra posición.

La versión mas simple podría ser esta:

<!DOCTYPE html>
<html lang="es">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Cómo usar la API de Geocoding de Google - Fish & Bits</title>
  </head>
  <body>
    <form id="demoform" action="#" method="post">
      <h1>Cómo usar la API de Geocoding de Google</h1>
      <label>Domicilio:
        <input type="text" name="domicilio">
      </label><br />
      <label>Municipio:
        <input type="text" name="municipio">
      </label><br />
      <label>Provincia:
        <select name="provincia">
          <option value="A Coruña">A Coruña</option>
          <option value="Araba">Araba</option>
          <!-- El resto de las provincias -->
          <option value="Zamora">Zamora</option>
          <option value="Zaragoza">Zaragoza</option>          
        </select>
      </label><br />
      <label>Código Postal:
        <input type="tel" name="cod_postal">
      </label><br />
      <button type="button" onclick="adivinaMiDireccion()">
        Adivina dónde estoy
      </button>
    </form>
	<script>
	  function adivinaMiDireccion() {
	    //TODO: Sigue leyendo el artículo
	  }
	</script>	
  </body>
</html>

¡Lo sé, lo sé! Da mucha penita ver un formulario en HTML mondo y lirondo. Si quieres una versión mas estilosa, la demo del artículo usa los componentes de Material Design de Google. Pero para centrarnos en lo que queremos demostrar aquí, es mejor no perderse en las decoraciones.

También usaremos Vanilla JavaScript por simplicidad y por que no es necesario usar jQuery ni ningún otro framework para resolver este problema.

De momento lo único que hemos hecho aquí es crear el formulario y asociar al botón una función en JavaScript que es donde vamos a crear la magia: adivinaMiDireccion()

Paso 2: Cómo obtener la posición actual

El primer paso consiste en obtener la posición actual. Para ello no vamos a usar los servicios de Geocoding, si no la funcionalidad de posicionamiento del navegador.

<script>
  function adivinaMiDireccion() {
    if ("geolocation" in navigator) {                 
      getMyPosition(function (pos) {
        console.log('Latitud: ' + pos.lat + ' Longitud: ' + pos.lng);
      });
      return true;
    }
    return false;
  }
  
  function getMyPosition(callback) {
    navigator.geolocation.getCurrentPosition(function (position) {
       var returnValue = {
         lat: position.coords.latitude,
         lng: position.coords.longitude
       }
       callback(returnValue);
    });
  }
</script>

getMyPosition() es la encargada de obtener la posición del navegador (asumiendo que el navegador lo soporta [línea #35]). Es una función asíncrona (todo lo que vamos a ver aquí es muy asíncrono), así que en vez de devolver un valor, se le pasa como parámetro una función a la que se llamará cuando la posición esté disponible. El valor entregado a esta callback está compuesto por la latitud y la longitud.

La callback de nuestro ejemplo lo único que va a hacer de momento es mostrar en la consola la latitud y longitud obtenidas.

Paso 3: Cómo convertir la posición en una dirección con la API de Geocoding

Para usar la API de Geocoding de Google, lo siguiente que tenemos que hacer es cargar el script de la API. Se podría hacer en la sección <head>...</head> de nuestro HTML pero debido a que en una implementación real querremos ocultar la clave de API de los servicios de Google, aquí vamos a hacerlo desde JavaScript.

function cargarScriptGeocode() {
  const geocode_script = document.createElement('script');
  geocode_script.src = 'https://maps.googleapis.com/maps/api/js?key=Tu-clave-de-API';
  geocode_script.defer = true;
  document.head.appendChild(geocode_script);
}

A esta función hay que llamarla al inicio de nuestra aplicación. El script se carga de forma asíncrona y esperamos que esté completamente cargado cuando vayamos a usar los servicios.

<script>
  function cargarScriptGeocode() {
    ...
  }
  ...
  cargarScriptGeocode();
</script>

En la línea #36 tendrás que poner tu clave de API de los servicios de Google. Al final del artículo se explica cómo crearla y protegerla de forma conveniente.

Ahora estamos listos para llamar a la API de Geocoding de Google y convertir nuestra posición actual en una dirección:

function adivinaMiDireccion() {
  if ("geolocation" in navigator) {                 
    getMyPosition(function (pos) {
      const geocoder = new google.maps.Geocoder();
      const latlng = new google.maps.LatLng(pos.lat, pos.lng);

      geocoder.geocode( {'latLng': latlng}, function (results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          if (results[0]) {
            console.log(results[0].formatted_address);
          } else {
            // No hay resultados
          }
        } else {
          console.warn('Geocoder failed due to: ' + status);
          // Error al invocar la API
        }
      });

    });
    return true;
  }
  return false;
}

En la línea #40 se hace la llamada clave: se llama al servicio de geocoding pasándole el parámetro latLng como entrada, lo que significa que estamos haciendo una operación de Geocoding inversa.

Una vez mas la llamada es asíncrona y lo que hacemos es pasar una función que se encargará de hacer algo con el resultado cuando esté disponible (líneas resaltadas). De momento lo que hacemos es mostrar en la consola la primera dirección devuelta, asumiendo que nos devuelve alguna.

La API de Geocoding nos permite hacer muchas mas cosas. Consulta aquí la guía de referencia de la API.

Paso 4: Mapear la respuesta de la API con nuestros campos

La estructura de la respuesta es bastante enrevesada (consulta la guía de referencia de la API). Además la API no nos devuelve una sola dirección sino que devuelve una lista de candidatas.

Para cada resultado devuelto (results[]) disponemos de un campo con la dirección formateada (formatted_address) pero además disponemos de los componentes individuales de esta dirección (address_components[]). A priori no sabemos que partes de la dirección nos serán devueltos ni en que orden, por lo que es necesario mapear la información de la API a una estructura mas acorde con nuestra interfaz de usuario.

En concreto vamos a usar este formato para convertir las direcciones devueltas por la API de Geocoding:

let address_info = {
     lat: 0,
     lng: 0,
     calle: '',
     lugar: '',
     numero: '',
     municipio: '',
     provincia: '',
     cod_postal: '',
     comunidad: '',
     pais: '',
     direccion: ''};

Y vamos a crear una función que se encargue de mapear uno de los resultados devueltos por la API (results[...].address_coponents) en la estructura anterior:

function decodeAddress(components) {
  let address_info = {
     lat: 0,
     lng: 0,
     calle: '',
     lugar: '',
     numero: '',
     municipio: '',
     provincia: '',
     cod_postal: '',
     comunidad: '',
     pais: '',
     direccion: ''};
  for (let i = 0; i < components.length; i++) {
    if (components[i].types[0] == "locality") {
      address_info.municipio = components[i].long_name;
    } else if (components[i].types[0] == "country") {
      address_info.pais = components[i].long_name;
    } else if (components[i].types[0] == "street_address") {
      address_info.calle = components[i].long_name;
    } else if (components[i].types[0] == "route") {
      address_info.lugar = components[i].long_name;
    } else if (components[i].types[0] == "street_number") {
      address_info.numero = components[i].long_name;
    } else if (components[i].types[0] == "postal_code") {
      address_info.cod_postal = components[i].long_name;
    } else if (components[i].types[0] == "administrative_area_level_1") {
      address_info.comunidad = components[i].long_name;
    } else if (components[i].types[0] == "administrative_area_level_2") {
      address_info.provincia = components[i].long_name;
    }
  }

  if (address_info.calle) {
    address_info.direccion = address_info.calle;
    if (address_info.numero) address_info.direccion += ' ' + address_info.numero;
  } else if (address_info.lugar) {
    address_info.direccion = address_info.lugar;
    if (address_info.numero) address_info.direccion += ' ' + address_info.numero;
  } else {
    address_info.direccion = 'Lugar sin nombre lat: ' + last_location_info.lat +  ' long: ' + last_location_info.lng;
  }

  // Google no devuelve provincia para estas Ciudades Autónomas
  if (address_info.comunidad == 'Ceuta' || address_info.comunidad == 'Melilla') {
    address_info.provincia = address_info.comunidad;
  }

  return address_info;
}

La función anterior debería ser capaz de devolver una dirección bastante completa, al menos para posiciones dentro del territorio español. En el campo address_info.direccion se unen el nombre de la vía y el número y en el peor de los casos se obtendrá un «Lugar sin nombre lat: xx.xxxx long: yy.yyyy».

Paso 5: Utilizando candidatos alternativos

Podríamos procesar siempre la primera dirección candidata devuelta por la API de Geocoding, pero habrá muchas situaciones en que ésta dirección no será la correcta. Por ejemplo puedo estar en un edificio que de a una calle por la fachada y otra por la parte posterior, o puede que no sea claro si estoy en el número 5 o en el 7 de la calle.

La API nos devuelve todas la alternativas razonables, y la variabilidad además está condicionada por la exactitud de nuestra posición GPS.

Dado que la API devuelve varias candidatas, una buena opción para nuestro caso de uso es que cada vez que demos al botón nos muestre la siguiente dirección candidata de la lista.

En la implementación de la demo se ha hecho ésto y además se ha tenido en cuenta lo siguiente:

  • A lo sumo se usan las primeras cinco direcciones devueltas.
  • No se obtiene la posición del dispositivo y se llama a la API de Geocoding cada vez que se pulsa el botón. Si la última posición (y su traducción) se obtuvo hace menos de 10s, se reutiliza esta información (y se devuelve la siguiente dirección candidata).

Con esto podemos mostrar ya el JavaScript completo para esta demo:

<script>
  /* Almacena la información obtenida de la última posición examinada */
  var last_location_info = {ts:null, lat:null, lng:null, results:null, index:0};
  
  cargarScriptGeocode();
  
  function cargarScriptGeocode() {
    const geocode_script = document.createElement('script');
    geocode_script.src = 'https://maps.googleapis.com/maps/api/js?key=Tu-clave-de-API';
    geocode_script.defer = true;
    document.head.appendChild(geocode_script);
  }
  
  function adivinaMiDireccion() {
    myCurrentLocation(function (address) {
      if (address) {
        if (address.direccion)  demoform.domicilio.value  = address.direccion;
        if (address.municipio)  demoform.municipio.value  = address.municipio;
        if (address.provincia)  demoform.provincia.value  = address.provincia || 'A Coruña';
        if (address.cod_postal) demoform.cod_postal.value = address.cod_postal;
      } else {
        alert('En estos momentos no es posible obtener tu ubicación actual. Inténtalo de nuevo en unos minutos.');
      }
    });
  }
  
  function myCurrentLocation(renderer) {
    if ("geolocation" in navigator) {                      // El navegador soporta geolocalización?
     if (  (last_location_info.ts == null)                 // Nunca se ha obtenido la posición
        || ((Date.now() - last_location_info.ts) > 10000)  // La última posición se obtuvo hace mas de 10s
        || (last_location_info.results == null) ) {        // Al obtener la última posición no se obtuvieron resultados
  
       getMyPosition(function (pos) {                      // Obtener una nueva posición
         const geocoder = new google.maps.Geocoder();
         const latlng = new google.maps.LatLng(pos.lat, pos.lng);
  
         last_location_info.lat = pos.lat;
         last_location_info.lng = pos.lng;
         last_location_info.ts = Date.now();
         last_location_info.results = null;
                                                           // Convertir la posición en direcciones
         geocoder.geocode( {'latLng': latlng}, function (results, status) {
           if (status == google.maps.GeocoderStatus.OK) {
             last_location_info.index = 0;
             last_location_info.results = results;
             if (results[0]) {
               const address_info = decodeAddress(results[0].address_components);
               renderer(address_info);                     // Usar la primera dirección disponible
             } else {
               renderer(null);                             // No hay resultados
             }
           } else {
             console.warn('Geocoder failed due to: ' + status);
             renderer(undefined);                         // Error al invocar la API
           }
         });
       });
     } else {
       /*
        * Vamos a usar otro de los resultados obtenidos anteriormente.
        * Se usa el siguiente disponible hasta un máximo de 5
        */
       last_location_info.index++;
       if (  (last_location_info.index >= last_location_info.results.length)
          || (last_location_info.index >= 5) ) {
         last_location_info.index = 0;
       }
       const address_info = decodeAddress(last_location_info.results[last_location_info.index].address_components);
       renderer(address_info);                             // Usar la siguiente dirección disponible
     }
     return true;                                          // Servicios de geolocalización disponibles (llamada síncrona)
    }
    return false;                                          // Servicios de geolocalización NO disponibles (llamada síncrona)
  }
  
  function getMyPosition(callback) {
    navigator.geolocation.getCurrentPosition(function (position) {
       var returnValue = {
         lat: position.coords.latitude,
         lng: position.coords.longitude
       }
       callback(returnValue);
    });
  }
  
  function decodeAddress(components) {
    let address_info = {
       lat: last_location_info.lat,
       lng: last_location_info.lng,
       calle: '',
       lugar: '',
       numero: '',
       municipio: '',
       provincia: '',
       cod_postal: '',
       comunidad: '',
       pais: '',
       direccion: ''};
    for (let i = 0; i < components.length; i++) {
      if (components[i].types[0] == "locality") {
        address_info.municipio = components[i].long_name;
      } else if (components[i].types[0] == "country") {
        address_info.pais = components[i].long_name;
      } else if (components[i].types[0] == "street_address") {
        address_info.calle = components[i].long_name;
      } else if (components[i].types[0] == "route") {
        address_info.lugar = components[i].long_name;
      } else if (components[i].types[0] == "street_number") {
        address_info.numero = components[i].long_name;
      } else if (components[i].types[0] == "postal_code") {
        address_info.cod_postal = components[i].long_name;
      } else if (components[i].types[0] == "administrative_area_level_1") {
        address_info.comunidad = components[i].long_name;
      } else if (components[i].types[0] == "administrative_area_level_2") {
        address_info.provincia = components[i].long_name;
      }
    }
  
    if (address_info.calle) {
      address_info.direccion = address_info.calle;
      if (address_info.numero) address_info.direccion += ' ' + address_info.numero;
    } else if (address_info.lugar) {
      address_info.direccion = address_info.lugar;
      if (address_info.numero) address_info.direccion += ' ' + address_info.numero;
    } else {
      address_info.direccion = 'Lugar sin nombre lat: ' + last_location_info.lat +  ' long: ' + last_location_info.lng;
    }
  
    // Google no devuelve provincia para estas Ciudades Autónomas
    if (address_info.comunidad == 'Ceuta' || address_info.comunidad == 'Melilla') {
      address_info.provincia = address_info.comunidad;
    }
  
    return address_info;
  }
</script>   

Algunas aclaraciones adicionales para entender bien el código anterior:

  • Las líneas #47 a #56 son el renderer, es decir lo que se encarga de pintar en la interfaz de usuario los valores obtenidos. Esta parte será altamente dependiente de cada aplicación y es posible que en una misma aplicación haya varios renderers. El resto del código es bastante genérico.
  • La función que haga de renderer debe estar preparada para recibir valores null o undefined en el parámetro address, dado que no siempre seremos capaces de llamar a este callback con una dirección válida.
  • last_location_info es la variable global en la que almacenamos la última posición obtenida y las direcciones candidatas devueltas por la API de Geocoding. Es interesante explorar su contenido en la consola de JavaScript del navegador.
  • Las líneas #91 a #101 se encargan de obtener la siguiente dirección disponible. En la línea #62 se decide volver a obtener la posición si la última se obtuvo hace mas de 10 segundos. Quizá en tu caso los requerimientos sean otros.

Descárgate el código

Te puedes descargar el código fuente de la demo para usarlo en tu proyecto. Se cede con licencia LGPL v3 así que feel free!

Cómo crear la clave de API para los servicios de Google

En este artículo Google te explica detalladamente como crear una clave de API restringida. ¿Por qué restringida? Pues porque su uso conlleva (o puede conllevar) un coste, y no querrás que venga alguien por ahí y la use para sus propósitos particulares.

De todas formas aquí te doy las claves para llevar a cabo estos pasos.

Para empezar, tienes que iniciar sesión con una cuenta de Google. Una vez que lo hayas hecho vete a la consola de Cloud:

https://console.cloud.google.com/

Lo primero es tener un proyecto, y para crear un proyecto tendrás que aportar una tarjeta de crédito/débito. Ya se que no vas a tener mas de 40.000 usos al mes, pero Google no activará los servicios hasta que no vea que eventualmente podrá cobrar lo que gastes por encima del crédito gratuito.

Segundo paso: habilitar las APIs que vas a necesitar. Se hace desde el menú de APIS y servicios de la consola. Busca arriba el botón + HABILITAR APIS Y SERVICIOS.

Busca estas dos APIs y si no las tienes habilitadas hazlo ahora:

  • Maps JavaScript API
  • Geocoding API

Las APIs están habilitadas a nivel de proyecto, así que no pasa nada por que tengas habilitadas APIS adicionales. Si debes asegurarte que al menos esas dos lo están.

Lo siguiente será crear unas credenciales desde el menú homónimo de la parte de APIS y servicios. Las credenciales van a permitir que nuestra aplicación se presente ante Google como perteneciente a éste proyecto, y por tanto quede habilitada o restringida a los que configuremos en la consola de Cloud.

De los diferentes tipos de credenciales que podemos crear (+ CREAR CREDENCIALES), vamos a crear una Clave de API.

Google nos propone una clave con un chorizo de letras y números. A continuación tenemos que darle a RESTRINGIR CLAVE.

Dentro de Restricciones de aplicación, lo mas usual es que restrinjamos el uso de la clave a ciertos «URL referentes HTTP (sitios web)«.

En la sección de Restricciones de sitios web vamos añadiendo las URLs que pueden lícitamente usar la clave de API. Puede ser mas o menos genérico. Lo ideal es restringirlo todo lo posible. Ejemplos de URLS (de menos a mas restringidas):

https://mi-sitio.com/*

https://mi-sitio.com/mi-aplicacion-web/*

https://mi-sitio.com/mi-aplicacion-web/mi-pagina-que-usa-el-servicio.php

La misma clave de API puede ser usada por varios referentes. Mi consejo es que todos los referentes de una misma clave provengan de la misma aplicación web, y que en el nombre de la clave de API menciones dicha aplicación web.

Es fácil crear una clave separada para cada aplicación que tengamos. No es necesario crear un proyecto para cada una.

El siguiente paso es restringir el uso de la clave a ciertas APIS. Eso se hace en la sección Restricciones de API seleccionando la opción Restringir clave.

De la lista de APIs del desplegable, selecciona (solo) estas dos:

  • Maps JavaScript API
  • Geocoding API

Y como último paso no te olvides de GUARDAR tus cambios.

Comprueba en el listado de APIS y Servicios > Credenciales que tu clave de API aparece. Pasa el ratón por encima de URLs de referencia HTTP, 2 API. Deberías poder ver los datos que acabas de configurar. Si es así, usa el icono de copiar para llevarte el chorizo de la clave y pegarlo en tu código, como parámetro key en geocode_script.src

Con esto debería ser suficiente para que tu aplicación funcione, pero te dejo aquí un último enlace de Google útil para hacer troubleshooting de los problemas que puedas tener al usar la API:

https://developers.google.com/maps/documentation/javascript/error-messages

Bonus Track: Fijar cuotas de uso

Lo que viene a continuación no es estrictamente necesario para poner en servicio la funcionalidad de Geocoding en tu aplicación. Sin embargo, si el hecho de que en tu proyecto aparece tu tarjeta de crédito te quita un poco el sueño, entonces esta sección es para ti.

Por mucho que quieras ocultar la clave de API que usa tu aplicación, será posible obtenerla. No obstante si has seguido los pasos para restringirla y has usado referentes muy poco genéricos, es muy poco probable que alguien con oscuras intenciones pueda hacer un uso no autorizado de tu clave … y de tu dinero.

Para asegurarnos de que no nos va a ocurrir nada inesperado con nuestra facturación y que no nos vamos a encontrar de repente con una factura de miles de euros, hay que establecer cuotas de uso.

En Google Cloud Platform esto se hace desde IAM y administración > Cuotas:

https://console.cloud.google.com/iam-admin/quotas?hl=es

Busca y clica en Geocoding API en la columna de Servicio (en cualquiera de las líneas). Esto te llevará a la sección en la que puedes modificar las cuotas para este servicio.

De acuerdo a los precios actuales, las primeras 40.000 peticiones quedan dentro de nuestro crédito gratuito. Voy a explicar como configuraría las cuotas para evitar que una demo como la mía (que no tiene un propósito comercial), pueda llegar a generar coste.

Despliego Requests y veo las cuotas que puedo establecer para este grupo:

  • Request al día (por defecto ilimitado)
  • Request por minuto (por defecto 3000)
  • Request por minuto por usuario (por defecto ilimitado)

Las modifico de la siguiente forma:

  • Request al día – Límite: 1.000
  • Request por minuto – Límite: 60
  • Request por minuto por usuario – Límite: 6

¿Cuál es el razonamiento? Bueno, la aplicación esta construida de forma que no obtiene una nueva posición (y por tanto no la convierte en dirección) si la última posición se obtuvo hace menos de 10 segundos. Eso significa que un mismo usuario (usando la demo de forma interactiva) no podría generar mas de 6 peticiones en un mismo minuto.

De mis estadísticas de uso se que no suelo tener un gran número de usuarios simultáneos en mi blog. 10 usuarios viendo la demo de forma simultánea sería algo inusitado. Esto nos da un límite de 60 por minuto como razonable.

El número de 1.000 por día viene de un razonamiento inverso. No quiero tener mas de 40.000 peticiones al mes, por lo que fijando un límite de 1.000 por día estoy dentro de los márgenes. Mis estadísticas de visitas me dicen además que este límite no va a comprometer a mis posibles lectores (que por cierto, ¡mil gracias por seguir ahí!).

Vayamos ahora a Premium plan web service requests y Premium plan Javascript API requests. No creo que tengas una subscripción Premium a Google Maps Platform y ahora mismo no es algo que puedas contratar, no obstante, lo mejor es que establezcas TODAS las cuotas a Limite: 0.

Hemos terminado con la API de Geocoding, vamos ahora a revisar las cuotas para la otra API habilitada en nuestra clave de API: Maps JavaScript API.

La cuotas para esta API son:

  • Maps loads al día (por defecto Ilimitado)
  • Maps loads por minuto (por defecto 30.000)
  • Maps loads por minuto por usuario (por defecto 60)

La demo no hace cargas de mapas de Google Maps así que realmente no necesito este servicio, no obstante no lo voy a dejar totalmente a cero dado que puede que quiera hacer algún experimento en un futuro próximo. No obstante debo establecer unos límite dado que la API key es pública y tiene habilitado este servicio.

Bien, el servicio de Geocoding con las cuotas actuales puede consumir 31 * $5 = $155. Esto nos deja $45 para maps, lo que a un precio de $7/1.000 peticiones nos permite algo mas de 6.000 peticiones al mes dentro del saldo promocional.

Configuro las cuotas de la siguiente manera:

  • Maps loads al día – Límite 200
  • Maps loads por minuto – Límite 60
  • Maps loads por minuto por usuario (por defecto 60)

Esto me permite probar con libertad la generación de mapas interactivos. Si montase una demo con este servicio tendría que balancear el coste entre ambas.

Esto es solo un ejemplo de cómo cómo configurar las cuotas. Tus requerimientos particulares pueden ser bien distintos. No obstante te aconsejo que siempre fijes algunos límites. Al menos a las métricas de peticiones máximas por día.

Bonus track 2: Ajustando el presupuesto

De la misma forma que la sección anterior, no es necesario leer esta parte para que tu proyecto funcione. Y una vez mas, aquí se va a hablar mas de pasta que de código.

Puede que estés usando los servicios de Geocoding con un propósito comercial y que por tanto para ti sea perfectamente aceptable incurrir en coste mas allá del crédito promocional del Google. Pero seguramente querrás establecer unos límites para que las cosas no se salgan del tiesto.

La forma de crear tiestos gestionados dentro de Google Cloud Platform es a través de presupuestos. Se accede desde Facturación > Presupuestos y alertas.

Crea tu primer presupuesto con + CREAR PRESUPUESTO y dale un nombre.

Puedes crear un presupuesto global para todos tus proyectos y para todos tus servicios, o solo para una parte. De todas formas si tienes proyectos heterogéneos mi consejo es que uses cuentas de Google separadas, lo que te permitirá tener cuentas de facturación separadas y crédito promocional en cada una de ellas.

En el segundo paso de creación del presupuesto puedes establecer tu límite de gasto. Pongamos por ejemplo que podemos sufragar 200€ extra de coste al mes para este servicio.

En el tercer paso vamos a crear alertas. Por defecto se crean cuando se alcanzan los umbrales del 50%, 90% y 100% respectivamente. Mi recomendación es que la alerta del 100% se establezca sobre la previsión de coste, en vez de sobre el coste real (Factor de activación). Esto nos ayudará a gestionar tráfico inesperado.

Por ejemplo, si el día 5 del mes recibimos una alerta que indica que se prevé alcanzar el límite de consumo de nuestro presupuesto mensual, deberíamos analizar nuestras estadísticas de tráfico para ver lo que está ocurriendo. Puede que debamos aumentar las cuotas porque tenemos mucho nuevo tráfico significativo, o puede que estemos recibiendo un ataque y debamos tomar medidas paliativas.

La misma alerta, el día 20 del mes, indicando que ya hemos alcanzado el 100% del presupuesto nos deja mucho menor margen de decisión y maniobra.

El presupuesto es una herramienta de gestión económica, pero no nos asegurará que el coste en Cloud sea inferior a un monto determinado. Google solo nos avisa de que hemos alcanzado el umbral del 100%, pero el servicio seguirá en uso y seguirá generando coste. La forma correcta de limitar el coste es establecer cuotas de uso.