2016 twenty-four merry days of Perl Feed

Geocoding the world at volume with open data

Geo::Coder::OpenCage - 2016-12-08

Open Geodata saves Christmas

Santa stood up from the desk and shook his head in disgust.

"No, this just won't do at all," he mumbled. The gentle melody of carols in the background couldn't hide the sense of disgust in his voice.

"What's the problem?" asked the Head Elf, while studiously double checking the present list on his clipboard.

"As if the massive bill wasn't enough, you should see the insane terms and conditions those clowns over at MegaCorp want us to agree to to use their geocoding services. This, my little friend, is the final straw. For years we've talked about it, and this year we are going to make the switch to using open geodata. I've seen more and more good things about the OpenStreetMap project. Thousands of contributors around the world, millions of edits per day. We shouldn't just be using open-source software, we should also be using open data!!!"

"Umm, Santa, you know I love open-source, but Christmas is only a few weeks away, and the engineers are already completely overloaded. OpenStreetMap is great, I agree, but we really don't have time to get anyone up to speed on it." answered the Head Elf. "Much as I dislike it, I think we'll have to stay with MegaCorp and agree to their terms and fees. If only there were some service that would let us use open geodata, but also have enterprise level reliability and almost no learning curve."

Across the room, Rudolph the reindeer looked up from his screen.

"We could use the OpenCage Geocoder", he said. "OpenCage provide a simple API to query multiple open geodata backends, including OpenStreetMap. It's ace. And there's a Perl module."

Rudolph picked up his eggnog, wandered over to the whiteboard and started taking them through some code:

use Geo::Coder::OpenCage;

# get a key at https://geocoder.opencagedata.com/
my $api_key = 'secret_key';
my $Geocoder = Geo::Coder::OpenCage->new(api_key => $api_key);

my $response = $Geocoder->geocode(location => 'the north pole');
# $response is hash ref to result set

if ($response->{total_results} > 0){
# grab the first result
my $result = $response->{results}[0];
    say "Formatted location name: " . $result->{formatted};
    say "long,lat: " . $result->{geometry}{lng} . ',' . $result->{geometry}{lat};
} else {
    say "no results found";
}

"That's nice, but as you may recall a few years back we stopped using addresses and switched to coordinates for finding the kids' homes. So what we really need is the opposite - to turn coordinates into locations. " said Santa.

"Yes, I know. I was just showing you a quick example. Have a look at this," replied Rudolph.

my $longitude = 2.1287224;
my $latitude = 41.4014067;

my $response = $Geocoder->reverse_geocode(lng => $longitude, lat => $latitude);
say $longitude . ',' . $latitude . " = " . $response->{results}[0]->{formatted};
# prints '2.1287224,41.4014067 = Carrer de Calatrava, 68, 08017 Barcelona, Spain'

"Wow, that's great. I love the way the address is formatted correctly. Even for a global business like ours getting little i18n details like that right is a huge pain."

Rudolph nodded in agreement. "Behind the scenes they use Geo::Address::Formatter, all the underlying templates are open source."

But wait, there's more

"Great stuff. This looks like it could work Rudolph. Let's go tell the engineers, there's still a lot to do. We need to use the coordinates to get all kinds of other data for the trip," said Santa.

"Like what?" asked Rudolph.

"Well, first we need to figure out the local time in each location. Then we'll need to determine when it gets dark there. Then we need to ..."

Rudolph let him talk for a few minutes, took a long drag of eggnog, and then said "Santa, the kids at OpenCage have solved all that. By default each result includes all kinds of information about the location already, they call them annotations"

my $lng = 2.1287224;
my $lat = 41.4014067;

my $response = $Geocoder->reverse_geocode(lng => $lng, lat => $lat);

# get first result
my $result = $response->{results}[0];
my $annotations = $result->{annotations};

# timezone info
say $annotations->{timezone};

# information about the local currency
say $annotations->{currency};

# time of sunrise and sunset
say $annotations->{sun};

# direct link to edit in OpenStreetMap
say $annotations->{OSM};

# and many more including what3words code, qibla orientation, geohash
# see the full list: https://geocoder.opencagedata.com/api#annotations

A broad grin spread across Santa's face as he said "Rudolph, this is genius! OpenCage will save us so much dev time, our most expensive resource. Wonderful."

"Yes. And best of all it's written in Perl. Basically they've created a thin layer of CPAN goodness on top of the massive, global OpenStreetMap community," replied Rudolph.

"And if you're looking for a final stocking stuffer there's even an OpenCage Perl 6 module already. So we'll be all set when we switch over to using Perl 6 for everything."

"I just revisited the project plan, Rudolph," interjected the Head Elf. "We should be good to go by Christmas. But not this Christmas."

Gravatar Image This article contributed by: Ed Freyfogle <edf@opencagedata.com>