Contacting the Mapzen API and geocoding a real location

After all that work to prepare for the response from the Mapzen API, we just have to call the correct endpoint and pass along the location.
This article is part of a sequence.
Project Example: Show Me Nearest Earthquakes
A step-by-step process of creating a project that downloads earthquake data, geocodes a user's location, and displays the nearest locations.
Table of contents

Getting started

This exercise assumes you've completed the previous exercise:

    compciv-2016
    └── projects
        └── show-me-where
            └── woz.py
            └── utils
                └── geocoding.py
                └── __init__.py

Testing out the credential via the browser

If your API key is something like this:

  search-ZzZzZz

Then you should be able to just call Mapzen's API via the browser:

Here's the endpoint URL:

  https://search.mapzen.com/v1/search

The location you want to search is specified via the text parameter. Pick a simple location for now:

  https://search.mapzen.com/v1/search?text=New+York

And the API key is specified via the api_key parameter – obviously replace it with your own key:

  https://search.mapzen.com/v1/search?text=New+York&api_key=search-zZzZzZ

And when you visit that via your browser, it should look something like this.

Add the creds_mapzen.txt file to your project

Just a simple text file with a single line: whatever key you got from the Mapzen API:

    compciv-2016
    └── projects
        └── show-me-where
            └── creds_mapzen.txt
            └── woz.py
            └── utils
                └── geocoding.py
                └── __init__.py

Test in iPython

Before we write and run the function, let's just pretend we're running the old-fashioned way, without importing utils.geocoding. Just running stuff straight from the interactive prompt.

No need to run all the other functions. We can try to contact Mapzen as if we hadn't written any other code.

Jump into ipython

>>> import requests
>>> MAPZEN_ENDPOINT =  'https://search.mapzen.com/v1/search'
>>> filename = 'creds_mapzen.txt'
>>> keytxt = open(creds_filename).read().strip()
>>> print(keytxt)
search-WHATEVER

OK, now let's make the call:

>>> somelocation = "New York NY"
>>> mapzenparams = {'api_key': keytxt,  'text': somelocation}
>>> resp = requests.get(MAPZEN_ENDPOINT, params = mapzenparams)
>>> print(resp.text)

Creating utils.geocoding.read_mapzen_credentials()

The function to read the Mapzen credentials is fairly straightforward. This goes inside the the utils/geocoding.py file because only the geocoding functions – the ones that contact Mapzen – actually need access to it.

def read_mapzen_credentials():
    creds_filename = "creds_mapzen.txt"
    keytxt = open(creds_filename).read().strip() # e.g. "search-blahblah"
    return keytxt

Changing fetch_mapzen_response() to get live data

OK, now we just have to alter one function to make things work: fetch_mapzen_response which is also in utils/geocoding.py

Remember, it looked like this.

def fetch_mapzen_response(location):
    """
    `location` is a string that will be passed onto Mapzen API for geocoding

    returns a text string containing JSON-formatted data from Mapzen
    """
    # ignore the location string for now
    SAMPLE_DATA_URL = 'http://www.compciv.org/files/datadumps/apis/mapzen/search-stanford.json'
    resp = requests.get(SAMPLE_DATA_URL)
    return resp.text

We don't want it to get canned data. We want it to talk to the Mapzen geocoder.

So refer to what you did when you tried it out in iPython above. Or heck, when you tried it via your web browser:

    https://search.mapzen.com/v1/search?text=New+York&api_key=search-zZzZzZ

(obviously, replace search-zZzZzZ with whatever your Mapzen API key is)

Here's a start – basically, fix SOME_URL to point to the right place.

def fetch_mapzen_response(location):
    """
    `location` is a string that will be passed onto Mapzen API for geocoding

    returns a text string containing JSON-formatted data from Mapzen
    """
    mykey = read_mapzen_credentials()
    my_params = {'text': location, 'api_key': mykey}
    resp = requests.get(SOME_URL, params = my_params)
    return resp.text

What you should have

Here's how you know what you have works.

Go to your project directory via the command-line, e.g.

cd ~/Desktop/compciv-2016/projects/show-me-where

Then, run iPython (I mean, sure you could go through woz.py if you want):

Your utils.geocoding.geocode function should just work. Even though you didn't touch it. Why? Because only fetch_mapzen_response was the part that wasn't doing its real job. Once you fixed it, by having it talk to the real API…everything else around it…stayed the same.

Just try it:

>>> from utils.geocoding import geocode
>>> g = geocode("WALLA WALLA WASHINGTON")
>>> print(g['label'])
Washington School, Walla Walla, WA
>>> print(g['longitude'], g['latitude'])
-118.35191 46.06847

Maybe you got something different…but you definitely should not be getting the Stanford data.

So what changed? Just having fetch_mapzen_response use the correct URL and parameters. Remember what the geocode function looks like:

    rawtext = fetch_mapzen_response(location)
    mydict = parse_mapzen_response(rawtext)
    # add the location string to mydict
    mydict['query_string'] = location
    # return the diccionary
    return mydict

The second line of that function:

    mydict = parse_mapzen_response(rawtext)

– does its job as long as rawtext is a text string that can be deserialized and fits Mapzen's standard format. Otherwise, none of the other steps in the geocode function body care what's going on in the internals of fetch_mapzen_response…and that's pretty much why we package things into different functions and files: to keep a separation of concerns.

This article is part of a sequence.
Project Example: Show Me Nearest Earthquakes
A step-by-step process of creating a project that downloads earthquake data, geocodes a user's location, and displays the nearest locations.