Learn how to extract and validate addresses using the Google Maps Geocoding API
If you need to ship or pickup an item for a customer you might need their address. But how do you verify if it exists?
Address information can consist out of street, house number, postal code, po box, city, state, country, etc. Using Flow and the Google Maps Geocoding API, there is no need to ask all this information separately.
Design your flow and capturing the address
Training the AI to contextually extract house numbers and cities using entities works, but it requires a lot of training data.
Even adding a hundred annotated examples might not give you a 100% result. In stead, it is far easier to use an Any text slot of the entity type Text.
Using the Any text you can capture any user input and use that within a code action to geo-code it to structured data.
Validating the address with the Google API
There are different providers, but for this example we'll show how to use the Google Maps Geocoding API to convert user input into structured address information.
To use the Geocoding API you need to get an API key. The API key is a unique identifier that is used to authenticate requests with Google for usage and billing purposes.
Writing the code action
The first step is getting the address information. Any text works the same way as any other params.
In the code example below, we simply receive the address and output it to the logging console.
async payload => {
const {
params,
user
} = payload
const { address } = params
const lastAddress = address[address.length - 1 ].value
console .info( 'The last address captured' , lastAddress)
}
Now that we have the address we can validate and transform it into structured address data using the Google API.
async payload => {
try {
const {
params,
user
} = payload
const { address } = params
const lastAddress = address[address.length - 1 ].value
// For this example we show the API key in code
// but best practice is to use Configuration
// https://flow.ai/docs/actions/code_configuration
const key= 'MY SECRET API KEY'
// Construct a Google API URL
const url= encodeURI ( `https://maps.googleapis.com/maps/api/geocode/json?address= ${lastAddress} &key= ${key} &language= ${user.profile.locale || 'en'} ` )
// Call the API
const { data } = await request(url)
const { status, results } = data
console .info( 'The API converted the address to' , results)
} catch (err) {
console .error( 'Failed to call the API' , err)
}
}
Below is a sample geocoding result, in JSON. Please check the Google documentation to find out about all the details of the response.
[
{
"address_components" : [
{
"long_name" : "1600" ,
"short_name" : "1600" ,
"types" : [ "street_number" ]
},
{
"long_name" : "Amphitheatre Pkwy" ,
"short_name" : "Amphitheatre Pkwy" ,
"types" : [ "route" ]
},
{
"long_name" : "Mountain View" ,
"short_name" : "Mountain View" ,
"types" : [ "locality" , "political" ]
},
{
"long_name" : "Santa Clara County" ,
"short_name" : "Santa Clara County" ,
"types" : [ "administrative_area_level_2" , "political" ]
},
{
"long_name" : "California" ,
"short_name" : "CA" ,
"types" : [ "administrative_area_level_1" , "political" ]
},
{
"long_name" : "United States" ,
"short_name" : "US" ,
"types" : [ "country" , "political" ]
},
{
"long_name" : "94043" ,
"short_name" : "94043" ,
"types" : [ "postal_code" ]
}
],
"formatted_address" : "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA" ,
"geometry" : {
"location" : {
"lat" : 37.4224764 ,
"lng" : -122.0842499
},
"location_type" : "ROOFTOP" ,
"viewport" : {
"northeast" : {
"lat" : 37.4238253802915 ,
"lng" : -122.0829009197085
},
"southwest" : {
"lat" : 37.4211274197085 ,
"lng" : -122.0855988802915
}
}
},
"place_id" : "ChIJ2eUgeAK6j4ARbn5u_wAGqWA" ,
"types" : [ "street_address" ]
}
]
Covering any edge cases
The Google API might return multiple results, so it's good to confirm the returned address with the user.
For this we extend the flows to handle edge cases like:
If the Google API returns an error
If the API did not give any valid results
If the API returns us multiple addresses
Below is an example what your final flow could look like.
Within the code action we send a Carousel component to display the results, and ask the user to verify the address.
async payload => {
try {
const {
params,
user
} = payload
const { address } = params
const lastAddress = address[address.length - 1 ].value
// Add the API key to the configuration
const key = await toolbelt.config.get( 'api_key' )
// Build url
const url= encodeURI ( `https://maps.googleapis.com/maps/api/geocode/json?address= ${lastAddress} &key= ${key} &language= ${user.profile.locale || 'en'} ` )
const { data } = await request(url)
const { status, results } = data
if (status !== 'OK' ) {
return trigger( 'INVALID_ADDRESS' )
}
/*
* Simple helper function to find a piece
* of address information within the API results
*/
const findAddressPart = ( result, part ) => {
const component = result.address_components.find( c => c.types.indexOf(part) !== -1 )
if (component) {
return component.short_name
}
return ""
}
// Create a carousel
const carousel = new Carousel()
for ( let i = 0 ; i < results.length; i++) {
const result = results[i];
// Create a card
const card = new Card({
title : result.formatted_address
})
const params = [
new Param( 'delivery_street' , findAddressPart(result, 'route' )),
new Param( 'delivery_zipcode' , findAddressPart(result, 'postal_code' )),
new Param( 'delivery_housenumber' , findAddressPart(result, 'street_number' )),
new Param( 'delivery_city' , findAddressPart(result, 'locality' )),
new Param( 'delivery_country' , findAddressPart(result, 'country' ))
]
card.addButton( new Button({
label : "Confirm" ,
type : 'event' ,
value : 'ADDRESS_CONFIRMED' ,
param : params
}))
carousel.addCard(card)
}
carousel.addQuickReply( new QuickReply({
type : 'event' ,
label : 'Try again' ,
value : 'DELIVERY_ADDRESS'
}))
return new Message( 'We do not support audio only' ).addResponse(carousel)
} catch (err) {
console .error( 'Failed to call the API' , err)
trigger( 'INVALID_ADDRESS' )
}
}
As you can see you can really create advanced use cases.
Read more
Working with entities
Creating code actions
Google Maps Geocoding API
View full article