Google Maps API Overview
The Google Maps Geocoding API is easy to understand and easy to use API. But first, we have to understand what geocoding is.
Geocoding is the process of converting addresses (like “1600 Amphitheatre Parkway, Mountain View, CA”) into geographic coordinates (like latitude 37.423021 and longitude -122.083739)…
The API has two endpoints:
- geocoding: Performs the process described above
- reverse geocoding: Performs the opposite of the process described above (converts coordinates to an address)
{6 items "address_components":[8 items 0:{3 items "long_name":"279" "short_name":"279" "types":[...]1 item } 1:{3 items "long_name":"Bedford Avenue" "short_name":"Bedford Ave" "types":[...]1 item } 2:{3 items "long_name":"Williamsburg" "short_name":"Williamsburg" "types":[...]2 items } 3:{3 items "long_name":"Brooklyn" "short_name":"Brooklyn" "types":[...]3 items } 4:{3 items "long_name":"Kings County" "short_name":"Kings County" "types":[...]2 items } 5:{3 items "long_name":"New York" "short_name":"NY" "types":[...]2 items } 6:{3 items "long_name":"United States" "short_name":"US" "types":[...]2 items } 7:{3 items "long_name":"11211" "short_name":"11211" "types":[...]1 item } ] "formatted_address":"279 Bedford Ave, Brooklyn, NY 11211, USA" "geometry":{3 items "location":{2 items "lat":40.71423350000001 "lng":-73.9613686 } "location_type":"ROOFTOP" "viewport":{2 items "northeast":{2 items "lat":40.71558248029151 "lng":-73.9600196197085 } "southwest":{2 items "lat":40.71288451970851 "lng":-73.96271758029151 } } } "place_id":"ChIJT2x8Q2BZwokRpBu2jUzX3dE" "plus_code":{2 items "compound_code":"P27Q+MF Brooklyn, New York, United States" "global_code":"87G8P27Q+MF" } "types":[6 items 0:"bakery" 1:"cafe" 2:"establishment" 3:"food" 4:"point_of_interest" 5:"store" ] }
For one address the API returns a list of possible address items (this sample is only one item from the list) and inside the response, there is information that:
- divides different parts of the address
- provides latitude & longitude
- shows viewport coordinates for the map
- gives you the Google+ code
- has location tags for the address type (i.e bakery, cafe, food)
Later, we’ll use the API to retrieve coordinates for an address, and then use the coordinates to retrieve more exciting information. The API is simple, but it is normally used in conjunction with another API or additional functionality.
Google Maps API Pricing
Is the Google Maps API free?
The Google Maps Geocoding API is free for the first 500 requests a month. After 500, each request will cost $0.01. Pricing for the API can be found on the API dashboard page.
Notice the Pro subscription is a small step from Basic, and it would be worth the time to accurately predict the number of requests your application will need. Five-thousand requests at Basic would be $45 for the month compared with only $30 a month with the Pro subscription. This is because the cost of each request above the quota is cheaper with the Pro subscription.
The Basic subscription will be sufficient for the example later in the article.
How to use the Google Maps API in React
First, let’s get signed up to use the Google Maps Geocoding API on RapidAPI.
1. Sign Up For a Free Account on RapidAPI
To subscribe to the geocoding API, you will need an account. Visit RapidAPI to get signed up!
2. Subscribe to Google Maps Geocoding API
Earlier, I discussed the pricing for the API. Let’s revisit the pricing page on the API dashboard. Search for Google Maps Geocoding or follow this link to the subscription page.
Notice I have already subscribed to the Basic plan, therefore I have a link to Manage and View Usage that takes me to the developer dashboard.
On the dashboard, you can track your API usage in case you are concerned about approaching your quota for any of the APIs that you are subscribed to.
3. Create a React Component
As you may know, React is built using functional and class components. How APIs are called depends on which type of component you are using. If you are new to React and API calls you should check out this beginner tutorial to get started then come back here.
Below, I will give an example of calling the Google Maps Geocoding API in a functional component. We will use a similar technique when we build a small example app in the next section.
import React from 'react' const Main = () => { // initializes state let [latitude, setLatitude] = React.useState(-33.7560119) let [longitude, setLongitude] = React.useState(150.6038367) let [address, setAddress] = React.useState('') // searches for new locations const updateCoordinates = (e) => { e.preventDefault() const encodedAddress = encodeURI(address) // fetches data from our api fetch(`https://google-maps-geocoding.p.rapidapi.com/geocode/json?language=en&address=${encodedAddress}`, { "method": "GET", "headers": { "x-rapidapi-host": "google-maps-geocoding.p.rapidapi.com", "x-rapidapi-key": process.env.RAPIDAPI_KEY } }) .then(response => response.json()) .then(response => { setLatitude(response.lat) setLongitude(response.long) }) .catch(err => console.log(err)) } return ( <div> The latitude is {latitude} The longitude is {longitude} <form onSubmit={(e) => updateCoordinates(e)}> <div className="form-group"> <label htmlFor="address">Address</label> <input type="text" className="form-control" id="address" required aria-describedby="addressHelp" value={address} onChange={(e) => setAddress(e.target.value)} /> </div> <button className="btn mb-4 btn-primary" type='submit'>Search Location</button> </form> </div> ) } export default Main
Don’t try to implement this component into an existing app. Instead, let’s observe how the code is set up.
React Hooks
React hooks have become popular since their introduction in v16. 8.0. In the above component, we use the hook useState
to store values in the component (i.e latitude, longitude, address).
It’s common to see API calls used in the hook useEffect
because that hook can be configured to run right after the component mounts. This is how data can be retrieved from an external source for a component.
JSX
If you are familiar with JSX you notice that the component has a small form that accepts a string. This is the address
variable that is used in the API call to Google Maps Geocoding.
When the form is submitted the function updateCoordinates
is executed. For the sake of the example, the JSX displays the latitude and longitude coordinates that appear.
updateCoordinates
Due to the type of request that Google Maps Geocoding takes (GET) the submitted address must be encoded so it can be sent in the URL of the request. For example;
"https://google-maps-geocoding.p.rapidapi.com/geocode/json?language=en&address=164%20Townsend%20St.%252C%20San%20Francisco%252C%20CA"
The encoded address in the above URL is “164 Townsend St., San Francisco, CA”.
Encoding a string in this way handles the special characters (i.e spaces, apostrophes) that may be in the parameter that is sent with the base URL.
The API request uses Javascript’s built-in fetch
function. However, that code was pulled, more-or-less, directly from RapidAPI’s dashboard.
RapidAPI Dashboard
RapidAPI makes it easy to inspect API endpoints, parameters, and see code snippets for different languages and libraries. Navigate to Google Maps Geocoding API to take a look.
The dashboard has three sections. The first section shows the available endpoints.
Next to the endpoints are the parameters that are specific to the selected endpoint.
Finally, there are code snippets and example responses for selected endpoints on the right side of the dashboard.
In the example component above, I copied the code from the dashboard snippet for the Geocoding endpoint and made a few changes. One of the notable changes was swapping out my API key for an environment variable.
This is a vital step in securing APIs, but it is not always apparent how we are supposed to do it.
What can you build with the API?
Despite the simple API call above, calling the geocoding API in an application requires a little more context. Securing your secret API-keys is a high priority and it cannot be done if all the code lives on the front-end.
Furthermore, the Google Maps Geocoding API is typically used in conjunction with another API. A common example is to use the geocoding API with something like the Dark Sky Weather API. Our example will combine the Google Maps Geocoding API with the TripAdvisor API to find attractions around an inputted address.
Google Map API Example
View code repository on Github
To address the security of our API key and take advantage of modern frameworks, we’ll use Next.js to build our example app. The framework is used to build server-side rendering (SSR) Javascript applications.
Additionally, the framework includes functionality to create serverless functions that exist with our front-end code, but are separate from the frontend code in terms of visibility in the browser. This is perfect for securing an API key while making third-party API requests.
There will be some set-up overhead with the framework, but in the end, we’ll have a secure app that displays local attractions given an inputted address!
Prerequisites
There are a few items to have in check before starting. You will need to have:
- Node.js installed on your system
- Reputable text editor for writing the code
- Understand how to use the terminal (i.e Bash, Powershell) to execute commands
- Internet connection
- RapidAPI account
- Next.js account on ZEIT so we can test and develop locally
- Understanding of Javascript and ReactJS
1. Set Up Next.js Project
Make a new directory in your terminal or open your text editor in a fresh folder. I named my new folder rapidapi-geocoding-react
.
In the new directory issue the following commands:
npm init -y npm install --save react react-dom next
The first command initializes the project as a NodeJS module so we can begin downloading NPM modules.
The second command installs the modules we need.
Next, create a new directory named pages
. Next.js uses this directory to create pages for the application. Inside the directory, create the file index.js
. This will serve as the only page for the application.
We need to go into our package.json
file (it was created when we initialized the package) and change the scripts.
Open up package.json
and replace the scripts block with the following Next.js commands:
... "scripts": { "dev": "next", "build": "next build", "start": "next start" } ...
At this point, we could start the app by executing npm run dev
in the project root, but there’s no code in index.js
. Therefore, there will be an error. Instead, let’s add some code;
// index.js import Head from 'next/head' const Index = () => ( <> <Head> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" /> </Head> <div className="container-fluid grey"> <div className="row"> <div className="col"> <h1 className="text-center display-3">How To Use Google Geocoding API</h1> <p className="lead text-center">Find the top attractions in an area by entering a valid address below!</p> </div> </div> <style jsx>{` h1 { font-size: 3.5rem; font-weight: 200; } .grey { background: #EEE } `}</style> </div> </> ); export default Index;
It’s a fairly straightforward set-up if you know some Javascript and ReactJS. However, Next.js has an option to style components differently. The <style>
tag applies CSS to the given component, however, these are not global styles.
Despite the introduction to styling with Next.js, styling will not be one of the main focuses of this example, but you could learn more about it on Next.js’s website.
Now that we added a component, you can start the application by running npm run dev
. The title we added should appear when you navigate to http://localhost:3000
.
Let’s create a few more folders and files to round out the project;
- create the folder
components
in the root of the project and create the fileMap.js
inside the folder - create the files
.env.build
,now.json
, andnext.config.js
in the root of the project. Leave them empty for now. - Inside of
pages
create the folderapi
and inside of that folder make the filegeocoding.js
The project structure is now (excluding the node_modules
folder);
Next.js Command-Line Interface (CLI)
We can use the ZEIT Now CLI to test our project locally. Next.js applications allow us to create API routes for our app inside the pages/api
folder. Although it is inside of our main project the code is not visible with the front-end code (i.e index.js
).
We want to use our secret RapidAPI key, as an environment variable, inside the file geocoding.js
located in pages/api
and the ZEIT Now CLI helps us do that.
Download ZEIT’s Now CLI:
npm i -g now
To log in and set up the project add the code below to now.json
;
{ "build": { "env": { "RAPIDAPI_KEY": "@rapidapi_key" } } }
This code will make sense later when we add the actual RapidAPI key variable to .env.build
.
Login to Now with:
now login
An email will be sent to your ZEIT account’s email and you can verify.
To use the Now developer tools, the project needs to be deployed to ZEIT. I contacted their support team because it seemed strange that I had to deploy a website before creating it. Granted, the Now CLI is in BETA.
Regardless, some of the commands will error if the project is not linked to a URL for the account.
Now that you are logged in and verified run the command now
.
Follow the prompts. Do not link to an existing project and do not override the settings.
If you check the deployment on ZEIT, the deployment will error. This is ok because we are only building an example application. Later, you can choose to delete the deployment on ZEIT.
We can now run the development server with the Now CLI that injects local environment variables.
Before moving on, stop the current development server (Ctrl+C). In the next section, we will add our secret API-key to the environment variables.
2. Secure API Key
Earlier, we added code to now.json
. Now, let’s finish adding code to our other configuration files.
In next.config.js
add the code;
module.exports = { env: { RAPIDAPI_KEY: process.env.RAPIDAPI_KEY, }, }
Next, in .env.build
add the code;
# Development keys, for production we recommend Now Secrets RAPIDAPI_KEY=yourapikey
You can find your API key by looking at the code snippets on the RapidAPI dashboard. It’s the value for the header "x-rapidapi-key"
. You could locate your key by observing where I blocked my API key out in one of the above dashboard pictures (I blocked it out with a red rectangle).
We have connected three files;
now.json
.env.build
next.config.js
With these files, we have added the capability to use a secret API key in our Next.js application. This set-up is necessary for development, but in production, it’s recommended that the developer use Now Secrets.
The secret key is locally available in .env.build
. Non-secret and secret environment variables can be added to Next.js apps using the next.config.js
file. For the CLI to link these values together, and for deployment in the future, we need the now.json
file.
Remember, the motivation to use Next.js framework, in this case, is because of the ability to securely make third-party API calls in ReactJS without having to set-up a backend server.
Finally, we can execute now dev
in the project root to start the development server. The application should again be available at http://localhost:3000
, but this time, we have access to environment variables.
3. Call the Google Maps Geocoding API and TripAdvisor API
In the project root run npm install isomorphic-unfetch --save
. This package allows us to use the Javascript fetch functionality on the backend. This is important for our function in pages/api/geocoding.js
because it is not run in the browser.
import fetch from 'isomorphic-unfetch' export default async (req, res) => { // Destructure incoming request const { method, body } = req // formats incoming input to be used as URL const encodedAddress = encodeURI(body.address) // use switch to handle request type switch (method) { case 'POST': try { // Gets coordinates for input address const currentLocation = await fetch(`https://google-maps-geocoding.p.rapidapi.com/geocode/json?language=en&address=${encodedAddress}`, { "method": "GET", "headers": { "x-rapidapi-host": "google-maps-geocoding.p.rapidapi.com", "x-rapidapi-key": process.env.RAPIDAPI_KEY } }) // creates json object const locationData = await currentLocation.json(); // extracts needed location data const lat = locationData.results[0].geometry.location.lat const long = locationData.results[0].geometry.location.lng // gets attractions based on lat long variables const attractions = await fetch(`https://tripadvisor1.p.rapidapi.com/attractions/list-by-latlng?lunit=km¤cy=USD&limit=10&distance=10&lang=en_US&longitude=${long}&latitude=${lat}`, { "method": "GET", "headers": { "x-rapidapi-host": "tripadvisor1.p.rapidapi.com","x-rapidapi-key": process.env.RAPIDAPI_KEY } }) // creates json object const attractionsData = await attractions.json() // extracts list from response const attractionsList = attractionsData.data // returns data with HTTP status 200 res.status(200).json({ lat, long, attractionsList }) } catch (e) { // returns bad request error if something goes wrong res.status(400).send() } break default: // if request is not POST method return HTTP status code 405 res.setHeader('Allow', ['POST']) res.status(405).end(`Method ${method} Not Allowed`) } }
Instead of calling the API in the component like the example given in the section How to use the Google Maps API in React above, the third-party API calls will be done here.
I have left comments in the code and the function reads procedurally.
When the user inputs an address, a request (req) will be sent to this function (located at http://localhost:3000/api/geocoding). After encoding the address, the geocoding API is called and coordinates are returned. Next, the coordinates are used to call the TripAdvisor API. Both responses are converted to JSON objects.
The response (res) object is then sent back to the front end with the latitude, longitude, and local attraction objects that contain coordinates we can add to the map.
To use the TripAdvisor API, subscribe to it on the pricing page. The API allows the same amount of free requests as the Google Maps Geocoding API (500).
The application will come together once we have created the map component!
4. Add Map Component
The map component is built using react-google-maps. The library allows us to easily set-up a Google map with markers. Install the module in the project;
npm install react-google-maps --save
The code for Map.js
is;
import React from 'react' import { withScriptjs, withGoogleMap, GoogleMap, Marker } from "react-google-maps" import fetch from 'isomorphic-unfetch' const MapComponent = withScriptjs(withGoogleMap((props) => ( <GoogleMap defaultZoom={14} defaultCenter={{ lat: props.lat, lng: props.long }} center={{ lat: props.lat, lng: props.long }} > {props.isMarkerShown && <Marker shape="rectangle" position={{ lat: props.lat, lng: props.long }} />} {props.attractions.length > 1 && props.attractions.map((attraction, i) => { return <Marker key={`${attraction.location_id}-${i}`} position={{lat: Number(attraction.latitude),lng: Number(attraction.longitude)}} label={attraction.name} title={attraction.name} /> })} </GoogleMap> ))) const Main = () => { // initializes state let [latitude, setLatitude] = React.useState(-33.7560119) let [longitude, setLongitude] = React.useState(150.6038367) let [attractions, setAttractions] = React.useState([]) let [address, setAddress] = React.useState('') let [message, setMessage] = React.useState({}) // searchs for new locations const updateCoordinates = (e) => { e.preventDefault() setMessage({text: 'Loading..', variant: 'info'}) const data = { address } // fetches data from our api fetch('/api/geocoding', { method: 'POST', mode: 'cors', cache: 'no-cache', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }) .then(response => response.json()) .then(response => { // add data to state setAttractions(response.attractionsList) setLatitude(response.lat) setLongitude(response.long) setMessage({}) }) .catch(() => setMessage({text: 'Something went wrong..', variant: 'danger'}) ) } return ( <div> <p className={`alert alert-${message.variant}`}>{message.text}</p> <form onSubmit={(e) => updateCoordinates(e)}> <div className="form-group"> <label htmlFor="address">Address</label> <input type="text" className="form-control" id="address" required aria-describedby="addressHelp" placeholder="42 Wallaby Way, Sydney" value={address} onChange={(e) => setAddress(e.target.value)} /> <small id="addressHelp" className="form-text text-muted">The street address that you want to look-up, in the format used by the national postal service of the country concerned. Additional address elements such as business names and unit, suite or floor numbers should be avoided.</small> </div> <button className="btn mb-4 btn-primary" type='submit'>Search Location</button> </form> <MapComponent lat={latitude} long={longitude} attractions={attractions} isMarkerShown googleMapURL="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places" loadingElement={<div style={{ height: `100%` }} />} containerElement={<div style={{ height: `400px` }} />} mapElement={<div style={{ height: `100%` }} />} /> <style jsx>{` form { margin: 2rem; background: white; border-radius: 5px; padding: 1rem; } p { margin-left: 1rem; margin-right: 1rem; } `}</style> </div> ) } export default Main
There are two components in the file. The parent component, Main, holds the child component, MapComponent, and has a form to accept and send the inputted address.
React-google-maps has many different features that can be explored in its documentation. However, for our example, I stuck with the basics.
Next, we need to add the Map component to index.js
. In index.js
, import the code from components/Map.js
and add the component towards the bottom of the JSX.
index.js
should now be;
import Map from '../components/Map' // new import Head from 'next/head' const Index = () => ( <> <Head> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" /> </Head> <div className="container-fluid grey"> <div className="row"> <div className="col"> <h1 className="text-center display-3">How To Use Google Geocoding API</h1> <p className="lead text-center">Find the top attractions in an area by entering a valid address below!</p> <Map /> // new </div> </div> <style jsx>{` h1 { font-size: 3.5rem; font-weight: 200; } .grey { background: #EEE } `}</style> </div> </> ); export default Index;
(Optional) Add Google API Key
Without a Google API key in the MapComponent URL, the map will have an overlay and display ‘For development purposes only’. The application will still work, but this might be annoying.
To remove the overlay, you need to get an API key from Google. I am not going to walk you through that process. However, if you do obtain the API key it needs to be added to the googleMapUrl
prop on the MapComponent
. For example, the new URL would be;
"https://maps.googleapis.com/maps/api/js?key=YOURAPIKEY&v=3.exp&libraries=geometry,drawing,places"
After adding the API key, you can have a professional map again.
WARNING: Please set strict guidelines for this API-key on your Google Project account so it is not abused.
That completes the example application using Next.js! After a couple of configuration files, and three Javascript files, we have a useful application! I hope the code comments help your understanding and exploration of the files in the project.
Conclusion
We built an application that uses a popular framework Next.js to build a modern ReactJS application and secured the API to call other third-party APIs to obtain useful information.
I also snuck in some Bootstrap styling to give the application is a nice modern look. Don’t forget there are other APIs that could be combined with the Google Maps Geocoding API like the Dark Sky Weather API.
I hope the example app inspires new ideas for you to build functionality or full applications using other easily accessible APIs!
Lindsay says
What would the best way of securing the API key that is used in the googleMapURL?
“https://maps.googleapis.com/maps/api/js?key=YOURAPIKEY&v=3.exp&libraries=geometry,drawing,places”
Don’t want the API to be public in the URL
Jarrett Retz says
Hello Lindsay,
On your Google Cloud account, you can handle access to certain domains, IP addresses, and there are a couple of other options. Below is a link to an article on some of these restrictions and how to set them up.
This Google API key is not supposed to be kept out of view on the front end.
Thanks for reading!
https://cloud.google.com/blog/products/maps-platform/google-maps-platform-best-practices-restricting-api-keys
Jarrett Retz says
Let me clarify, this specific API key for this specific Google Maps usage can be visible. Just make sure that restrictions are set before putting it into production.