Explore the world with Google Maps APIs
Tags: python, node, api, webdev
Published: 2024-05-27 20:54:08

<!-- Explore the world with Google Maps APIs -->
<!-- address geocoding, time zone identification, walking directions -->


## TL;DR:
The US Memorial Day holiday is traditionally a time when many travel to visit friends or family for a long weekend in remembrance of military personnel who made the ultimate sacrifice while serving in the country's armed forces, and traveling makes me think of Google Maps and _its_ APIs. While there's a brief intro to one of the Maps APIs in a [post on API keys](https://dev.to/googleworkspace/getting-started-using-google-apis-api-keys-part-2-38i6), Maps needs its own treatment, so this is your _formal_ introduction to the [Maps Platform](https://mapsplatform.google.com). To avoid an overwhelming amount of content, we're exploring its _server-side_ APIs, those you'd access from a web app or mobile backend.

<!--[OLD Google Maps Platform](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yl28ado3xzy4wtl9cucd.jpg)-->
![Google Maps Platform](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fpjk3h7d8ezeupyok0m2.jpg)


## Introduction
Welcome to the blog focused on showing Python (and sometimes Node.js) developers how to use a variety of Google APIs. On this blog, you'll find content covering a broad variety of topics such as [serverless computing](https://dev.to/wescpy/a-broader-perspective-of-serverless-1md1), [generative AI with Gemini](https://dev.to/wescpy/series/27183), and Google credentials like [API keys](https://dev.to/wescpy/series/25404) and [OAuth client IDs](https://dev.to/wescpy/series/25403), the latter specifically for use with [Google Workspace (GWS) APIs](https://developers.google.com/gsuite). Other posts dive into a specific solution, such as _using_ one of those GWS APIs to [export Google Docs as PDF](https://dev.to/wescpy/export-google-docs-as-pdf-without-the-docs-api-9o4) files. This post exposes readers to several APIs from yet another product group, [Google Maps](https://developers.google.com/maps).

The platform features many _different_ services, APIs, and SDKs (~20), and covering them all isn't really "digestible" in one go. Maps is also a _visual_ product, so many of its services are on the client-side as one would expect. If you're a developer reading a blog covering APIs and frequently _using_ APIs however, there's a good chance you work on server-side software, so covering the Maps APIs accessible from that perspective makes the most sense here.

Maps services are [grouped into four distinct categories](https://mapsplatform.google.com/maps-products), each summarized below:


| Category | Description |
| --- | --- |
| **Maps** (_M_) | Static & dynamic mapping, Street View imagery, elevation, aerial/geospatial imagery, map tiles |
| **Routes** (_R_) | Location of roads; routing/directions for various transportation modes; traffic info, times & distances |
| **Places** (_P_) | Place & location information: details, search, lat-long coordinates, addressing & geolocation, time zones |
| **Environment** (_E_) | Solar energy potential, air quality indexes, location-based pollen/pollutant info & health recommendations |
<figcaption>Google Maps Platform service categories</figcaption>
&nbsp;

The server-side APIs are known as the [Web Service APIs](https://developers.google.com/maps/apis-by-platform#web_service_apis). There are 15 of them at the time of this writing, and that's _still_ too much to cover in a single post. To further whittle down what to cover, we're going to focus on those that are supported by the [Maps client libraries](https://developers.google.com/maps/web-services/client-library). The others require you to use raw REST and HTTP, and hopefully the Maps team will soon support those with their client libraries.

In the meantime, we can help you get started with supported APIs. Client libraries encapsulate much of the boilerplate and do a lot of the heavy lifting so developers can focus on using API features. At the time of this writing, they support the 7 APIs listed below and account for nearly a third of all Maps services about half of all Maps APIs:

1. **Directions API** (_R_)
1. Distance Matrix API (_R_)
1. Elevation API (_M_)
1. **Geocoding API** (_P_)
1. Roads API (_R_)
1. Places API (_P_)
1. **Time Zone API** (_P_)

Of the APIs listed, I'll be demonstrating the **bolded** ones in this post.


## Prerequisites

As with other Google APIs, there are several distinct steps that you must take before you can use them from your application:

1. **Get credentials** from DevConsole; Maps uses API keys
1. **Install client library** for your development language
1. **Enable desired API(s)** in developer's console ("DevConsole")

These actions are unrelated to each other, meaning you can do them in any order.


### Get credentials (API key)

The first task is to get an API key:
1. Go to the [DevConsole credentials page](https://console.cloud.google.com/apis/credentials)
1. Click **+ Create Credentials** at the top
1. Select **API key** and wait a few seconds for completion
1. Copy and save API key as a variable `API_KEY = '<YOUR-API-KEY>'` to `settings.py` for Python or `.env` for Node.js (may need to refresh credentials page and click **Show key** to see it)

| :warning: WARNING: Keep API keys secure |
|:---------------------------|
| Storing API keys in files (or hard-coding them for use in actual code or even assigning to environment variables) is for prototyping and learning purposes only. When going to production, put them in environment variables or in a secrets manager. Files like `settings.py` or `.env` containing API keys are susceptible. ***Under no circumstances*** should you [upload files like those to any public or private repo](https://www.gitguardian.com/glossary/remediate-sensitive-data-leaks-api-keys-hardcoded-source-code), [have sensitive data like that in TerraForm config files](https://spacelift.io/blog/terraform-secrets), [add such files to Docker layers](https://www.darkreading.com/cloud-security/docker-leaks-api-secrets-private-keys-cybercriminals), etc., as once your API key leaks, everyone in the world can use it. |

If you're new to Google developer tools, [_API keys_](https://dev.to/wescpy/series/25404) are one of the credentials types supported by Google APIs, and they're the _only_ type supported by Maps APIs. Other credentials types include [_OAuth client IDs_](https://dev.to/wescpy/series/25403), mostly used by GWS APIs, and _service accounts_, mostly used by Google Cloud (GCP) APIs.


### Install client library (Maps)

The core Maps client libraries are available in four languages:
1. [Java](https://github.com/googlemaps/google-maps-services-java)
1. [Python](https://github.com/googlemaps/google-maps-services-python)
1. [Go](https://github.com/googlemaps/google-maps-services-go)
1. [Node.js](https://github.com/googlemaps/google-maps-services-js)

| :memo: NOTE: Other client libraries |
|:---------------------------|
| In the documentation, you may find reference to additional client libraries, for example in C# and Objective-C. However, these are resources used to either access REST API interfaces directly or are custom-built for specific APIs like the [Address Validation API](https://developers.google.com/maps/documentation/address-validation/client_libraries), so they aren't part of the "core" Maps client libraries. |

Install the one for your development language, and any others if you work with more than one. Here are the commands for Python (2 or 3) and Node.js:

| Language | Command |
| --- | --- |
| **Python** | `pip install -U googlemaps html2text`  # (or `pip3`) |
| **Node.js** | `npm install core-js dotenv @googlemaps/google-maps-services-js` |
<figcaption>Maps client library installation commands</figcaption>
&nbsp;

Confirm all required packages have been installed correctly with these validation commands:

| Language | Command |
| --- | --- |
| **Python** | `python -c "import googlemaps, html2text"`  # (or `python3`) |
| **Node.js** | `node -e "require('@googlemaps/google-maps-services-js')"` |
<figcaption>Maps client library validation commands</figcaption>
&nbsp;

If they complete without error, the installation(s) succeeded and they're ready for use.


### Enable APIs (Maps)

Now it's time to enable the Maps APIs used in the samples. All Google APIs must be enabled before they can be used. While many Google APIs are free to use, Maps APIs are not. However, all users are granted a [free monthly "quota" of $200USD of usage](https://mapsplatform.google.com/pricing) before incurring billing. Review the [Maps Platform billing page](https://developers.google.com/maps/billing-and-pricing/billing) to understand all the terms and conditions, then create a billing account backed by some financial instrument like a credit card or trial credit as described on that billing page.

Once you have a billing account, the next step is to [create a project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#creating_a_project) and assign that billing account to that project. You can also reuse an existing project if you have one. Now you can enable the Maps APIs. There are generally three different ways of enabling Google APIs.

1. **DevConsole manually** -- Enable one API at a time by following these steps:
    - Go to [DevConsole](http://console.developers.google.com)
    - Click on **Library** tab and search for "Maps" to see all the Maps APIs
    - Scroll down and look for **Geocoding API**, **Time Zone API**, and **Directions API**
    - Click **Enable API** button for each API
1. **DevConsole link** -- You may be new to Google APIs or don't have experience enabling APIs in the DevConsole. If this is you, the above steps can be simplified with a single [DevConsole link (and click) that enables all three APIs](http://console.developers.google.com/start/api?id=geocoding-backend.googleapis.com,timezone-backend.googleapis.com,directions-backend.googleapis.com).
1. **`gcloud`/command-line** -- For those who prefer working in a terminal, you can enable APIs with a single command in the [Cloud Shell](https://cloud.google.com/shell) or locally on your computer if you [installed the Cloud SDK](https://cloud.google.com/sdk/install) (which includes the `gcloud` command-line tool [CLI]) and initialized its use. If this is you, issue the following command to enable all three APIs: `gcloud services enable geocoding-backend.googleapis.com timezone-backend.googleapis.com directions-backend.googleapis.com`. Confirm which APIs you've enabled in-all with `gcloud services list`.

Any which way you've enabled the APIs, it's time to look at code.


## Code samples

This section covers use of the three Maps APIs enabled above, the Geocoding, Time Zone, and Directions APIs. Let's start with the Geocoding API since it was previously covered in an [earlier post on API keys](https://dev.to/googleworkspace/getting-started-using-google-apis-api-keys-part-2-38i6).


### Maps Geocoding API

Available in the [repo](https://github.com/wescpy/google), the [`maps_geocode.py` script](https://github.com/wescpy/google/blob/main/maps/maps_geocode.py) is the same as from the other post on API keys: it takes an address and geocodes it to a latitude-longitude ("lat/long") pair or 2-tuple:

```python
'''
maps_geocode.py -- geocode address in Google Maps
'''
from __future__ import print_function
import googlemaps
from settings import API_KEY

ADDRESS = '1600 Amphitheatre Pkwy 94043'
GMAPS = googlemaps.Client(key=API_KEY)
res = GMAPS.geocode(ADDRESS)[0]
geo = res['geometry']['location']
print('** Geocode for %r: (%s, %s)' % (ADDRESS, geo['lat'], geo['lng']))
```

The script creates an API client, passes in the API key for authorization, then calls the `geocode()` function with the target address. The lat/long is extracted from the payload and displayed with the origin address.

All scripts in this post are Python 2/3-compatible, meaning this code can help those on 2.x finally migrate to 3.x.

```
$ python3 maps_geocode.py
** Geocode for '1600 Amphitheatre Pkwy 94043': (37.4226277, -122.0841644)
```

The input is an imperfect address for Google's headquarters, but Maps still has enough information to do its job and returns the lat/long as requested. I don't use it in the script above, but the API also returns a more "formal" `formatted_address` field that you can use if desired:

```python
>>> res['formatted_address']
'1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA'
```

As I'm also learning JavaScript, here's my attempt porting the script to Node.js:


```javascript
/**
 * maps_geocode.js -- geocode address in Google Maps
 */
require('dotenv').config();
const { Client } = require("@googlemaps/google-maps-services-js");

const ADDRESS = '1600 Amphitheatre Pkwy 94043';
const GMAPS = new Client();
const args = {
  params: {
    key: process.env.API_KEY,
    address: ADDRESS,
  }
};

async function main() {
  const rsp = await GMAPS.geocode(args);
  const res = rsp.data.results[0];
  const geo = res.geometry.location;
  console.log(`** Geocode for "${ADDRESS}": (${geo.lat}, ${geo.lng})`);
}

main();
```
You'll find [this new script in the repo](https://github.com/wescpy/google/blob/main/maps/maps_geocode.js), and running it results in nearly the same output as the Python version:

```
$ node maps_geocode.js
** Geocode for "1600 Amphitheatre Pkwy 94043": (37.4226277, -122.0841644)
```

For those who prefer a modern ECMAScript module, here's the equivalent `.mjs` file, which is [also in the repo](https://github.com/wescpy/google/blob/main/maps/maps_geocode.mjs):

```javascript
/**
 * maps_geocode.mjs -- geocode address in Google Maps
 */
import dotenv from "dotenv";
import { Client } from "@googlemaps/google-maps-services-js";

dotenv.config();
const ADDRESS = '1600 Amphitheatre Pkwy 94043';
const GMAPS = new Client();
const args = {
  params: {
    key: process.env.API_KEY,
    address: ADDRESS,
  }
};

async function main() {
  const rsp = await GMAPS.geocode(args);
  const res = rsp.data.results[0];
  const geo = res.geometry.location;
  console.log(`** Geocode for "${ADDRESS}": (${geo.lat}, ${geo.lng})`);
}

main();
```

Take my word for it that its output is identical to the CommonJS version. The remaining samples are only in Python, and you can use this example to extrapolate porting the others to Node.js.

Next is the Time Zone API, which is a natural follow-up to the Geocoding API because it requires the lat/long coordinates of a location to determine its time zone.


### Maps Time Zone API

The [`maps_tzone.py` script found in the repo](https://github.com/wescpy/google/blob/main/maps/maps_tzone.py) takes a geolocation and returns its time zone and offset from GMT/UTC:

```python
'''
maps_tzone.py -- geocode address and get Google Maps time zone
'''
from __future__ import print_function
import googlemaps
from settings import API_KEY

ADDRESS = '1600 Amphitheatre Pkwy 94043'
GMAPS = googlemaps.Client(key=API_KEY)
rsp = GMAPS.geocode(ADDRESS)[0]['geometry']['location']
rsp = GMAPS.timezone((rsp['lat'], rsp['lng']))

offset = rsp['rawOffset'] + rsp['dstOffset']
sign = '-' if offset < 0 else '+'
offset, frac = divmod(abs(offset), 3600)
frac_str = str(round(frac/3600, 2))[1:] if frac else ''
tz_abbr = ''.join(c[0] for c in rsp['timeZoneName'].split())
print('** Time zone for %r:' % ADDRESS, rsp['timeZoneId'],
        '(%s/GMT%s%s%s)' % (tz_abbr, sign, offset, frac_str))
```

This script starts with a similar recipe to `maps_geocode.py`, and extends it after the geocoding takes place. An additional call to `timezone()` passing in the resulting geocode returns several key fields:

| Field | Description | Example |
| --- | --- | --- |
| **`rawOffset`** | Number of seconds away from GMT/UTC; positive if ahead of UTC, negative if behind |  `-28800` (for GMT-8) |
| **`dstOffset`** | Daylight saving time adjustment (in seconds) from standard GMT offset | `3600` (for 1-hour DST offset) |
| **`timeZoneId`** | [IANA time zone identifier](https://wikipedia.org/wiki/List_of_tz_database_time_zones) in "continent/locale" format | `America/Los_Angeles` (for PST/GMT-8 or PDT/GMT-7) |
| **`timeZoneName`** | Localized descriptive time zone name | `Pacific Daylight Time` (for GMT-7) |
<figcaption>Key fields returned by <code>geocode()</code> function</figcaption>
&nbsp;

Here's the output running this script:

```
$ python3 maps_tzone.py
** Time zone for '1600 Amphitheatre Pkwy 94043': America/Los_Angeles (PDT/GMT-7)
```

The `rawOffset` is combined with any possible DST adjustment (`dstOffset`) for the current time zone offset (in seconds) away from GMT. The `sign` variable tracks whether the time zone is ahead of GMT or behind. The overall offset is then split up into an hourly `offset` and a `frac`tional remainder, if any -- this applies to time zones that don't start a multiple of hours away from UTC. For example, replacing the Google headquarters address with that of its Bangalore office reveals that India Standard Time isn't on an hourly boundary away from GMT; it's further offset by a half-hour:

```
$ python3 maps_tzone-india.py
** Time zone for '3 Old Madras Rd, Bengaluru 560016 IN': Asia/Calcutta (IST/GMT+5.5)
```

For an _even more interesting_ time zone, change the address to that of the Pashupatinath Temple, a well-known Hindu temple in Kathmandu:

```
$ python3 maps_tzone-nepal.py
** Time zone for 'Pashupati Nath Road, Kathmandu 44600 NP': Asia/Katmandu (NT/GMT+5.75)
```

You're reading it correctly: Nepal Time is ahead of India Standard time by another 15 minutes, totaling 5.75 hours ahead of GMT, but this script (via `frac` & `frac_str`) can handle scenarios like these from south Asia. **NOTE:** There are no files in the repo named `maps_tzone-india.py` and `maps_tzone-nepal.py`... I merely copied `maps_tzone.py` to different files and changed the `ADDRESS` in each for illustrative purposes only. Create your own versions and try different addresses as you see fit.

Now let's move on to the final sample using the Directions API.


### Maps Directions API

The Directions API returns driving (default), walking, cycling, or public transit directions to get from point A to point B. The sample below, `maps_wlkdir.py`, also found [in the repo](https://github.com/wescpy/google/blob/main/maps/maps_wlkdir.py), calculates the walking directions, distance, and time to walk from one side of Google's main New York office building to the other side but from the outside rather than through the building itself:

```python
'''
maps_wlkdir.py -- get Google Maps walking directions
'''
from __future__ import print_function
from datetime import datetime
import googlemaps
from html2text import html2text
from settings import API_KEY

ADDRESSES = ('111 8th Ave, New York', '76 9th Ave')
GMAPS = googlemaps.Client(key=API_KEY)
rsp = GMAPS.directions(*ADDRESSES, mode='walking',
        departure_time=datetime.now())
dirs = rsp[0]['legs'][0]

print('** Walking directions...')
print('STARTING from:', dirs['start_address'])
print('CONCLUDING at:', dirs['end_address'])
print('DISTANCE:', dirs['distance']['text'])
print('DURATION:', dirs['duration']['text'])
print('DIRECTIONS:')
for i, step in enumerate(dirs['steps']):
    print('\t%d.' % (i+1), html2text(
        step['html_instructions']).strip().replace('\n\n', '\n\t'))
```

This script relies on a 3rd-party package, `html2text`, to convert the directions into plain text for our command-line script because they only come in HTML from the API.

The `directions()` function is called with the origin and destination addresses, the desired transportation `mode`, and the `departure_time` used by the API to determine the duration based on any extra traffic that may be around on that day at that time.

Running this script results in the following output:

```
$ python3 maps_wlkdir.py
** Walking directions...
STARTING from: 111 8th Ave, New York, NY 10011, USA
CONCLUDING at: 76 9th Ave, New York, NY 10011, USA
DISTANCE: 0.2 mi
DURATION: 4 mins
DIRECTIONS:
        1. Head **southwest** on **8th Ave** toward **W 15th St**
        2. Turn **right** onto **W 15th St**
        3. Turn **right** onto **9th Ave**
        Destination will be on the right
```


## Summary

Google provides a wide variety of developer tools and APIs for users to integrate their technologies programmatically. There is a definite bias towards GCP and GWS APIs on this blog because of my personal experience as a member of both of those teams during my time at Google, but Maps is another API family that deserves some attention too. This post provides a basic introduction to several of its server-side APIs to help you get your users where they need to go as well as get information about places found on Maps.

If you find yourself needing to know how to use these APIs, I hope this post helps kick off your journey into the Maps family of APIs. If you find any errors or have suggestions on content you'd like to see in future posts, be sure to leave a comment below, and if your organization needs help integrating Google technologies via its APIs, reach out to me by submitting a request at <https://cyberwebconsulting.com>. Lastly, below are links relevant to the content in this post for further exploration.


## References

This post covered quite a bit, so there is a good amount of documentation to link you to:

### Blog post code samples
- [Maps APIs only](https://github.com/wescpy/google/maps)
- [All featured APIs](https://github.com/wescpy/google)

### Google Maps Platform
- [Platform home](https://mapsplatform.google.com)
- [Platform pricing](https://mapsplatform.google.com/pricing)
- [Detailed pricing](https://developers.google.com/maps/billing-and-pricing/pricing)
- [Developers home](https://developers.google.com/maps)
- [Developers docs](https://developers.google.com/maps/documentation)

### Google Maps APIs
- [Maps Web Service APIs](https://developers.google.com/maps/apis-by-platform#web_service_apis)
- [Choosing a Maps API](https://developers.google.com/maps/documentation/api-picker)
- [Getting & using API keys](https://developers.google.com/maps/documentation/geocoding/get-api-key)
- [API keys best practices](https://developers.google.com/maps/api-security-best-practices)
- [API quotas & limits](https://developers.google.com/maps/faq#usage_apis)

### Maps APIs client libraries
- [Client libraries & supported APIs](https://developers.google.com/maps/web-services/client-library)
- [Python client library](https://github.com/googlemaps/google-maps-services-python)
- [Node.js client library](https://github.com/googlemaps/google-maps-services-nodejs)

### Maps Geocoding API
- [Geocoding API home](https://developers.google.com/maps/documentation/geocoding)
- [Geocoding getting started](https://developers.google.com/maps/documentation/geocoding/start)

### Maps Time Zone API
- [Time Zone API home](https://developers.google.com/maps/documentation/timezone)
- [Time Zone getting started](https://developers.google.com/maps/documentation/timezone/start)

### Maps Directions API
- [Directions API home](https://developers.google.com/maps/documentation/directions)
- [Directions getting started](https://developers.google.com/maps/documentation/directions/start)

### Other Google Maps content by the author
- [Getting started using Google APIs: API Keys (Part 2/2)](https://dev.to/googleworkspace/getting-started-using-google-apis-api-keys-part-2-38i6) post
- [Accessing Google Maps from a spreadsheet?!?](http://goo.gl/oAzBN9) video

---
<small>
**WESLEY CHUN**, MSCS, is a [Google Developer Expert](https://developers.google.com/experts) (GDE) in Google Cloud (GCP) &amp; Google Workspace (GWS), author of Prentice Hall's bestselling ["Core Python"](https://corepython.com) series, co-author of ["Python Web Development with Django"](https://withdjango.com), and has written for Linux Journal & CNET. He runs [CyberWeb](https://cyberwebconsulting.com) specializing in GCP & GWS APIs and serverless platforms, [Python & App Engine migrations](https://appenginemigration.com), and Python training & engineering. Wesley was one of the original Yahoo!Mail engineers and spent 13+ years on various Google product teams, speaking on behalf of their APIs, producing sample apps, codelabs, and videos for [serverless migration](http://bit.ly/3xk2Swi) and [GWS developers](http://goo.gl/JpBQ40). He holds degrees in Computer Science, Mathematics, and Music from the University of California, is a Fellow of the Python Software Foundation, and loves to travel to meet developers worldwide at conferences, user group events, and universities. Follow he/him [@wescpy](https://twitter.com/wescpy) & his [technical blog](https://dev.to/wescpy). Find this content useful? [Contact CyberWeb](https://forms.gle/bQiDMiGyGrrwv5sy5) if you may need help or [buy him a coffee (or tea)](http://buymeacoffee.com/wescpy)!
</small>