This exercise assumes you've completed the previous exercise:
compciv-2016 └── projects └── show-me-where └── woz.py └── utils └── geocoding.py └── __init__.py
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.
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
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)
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
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
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.