Fire Eagle : Python Walkthrough

Python Walkthrough

This page will get you started writing your first Fire Eagle application using Python. While this example will help you build a command-line Python application, many of the ideas and code will also apply if you're building a web-based application using Python (Django, for instance.) We will try to point out places where a web-based application will differ significantly from the command-line application described below.



Setup

Background

Fire Eagle uses OAuth to identify and authenticate applications and users that interact with the system. If you don't know anything about OAuth, read more about it here. Most of this walkthrough will focus on getting your application to authenticate a user using OAuth. Once that's done your application will be able to access Fire Eagle's API.

Python Stuff

Of course you'll need a Python interpreter. You'll also need to download the OAuth Python Library. The oauth.py file is the only thing you really need, but check out any other example files you find there as well, since they might also be interesting.

Put the oauth.py file some place that your Python script will be able to find it. Create a directory called fireeagle (anywhere you like) -- drop oauth.py in there and create a new file called my_app.py (using Idle if you're into that, or your favorite text editor).

Fire Eagle Stuff

Before we get started you need to tell Fire Eagle a little something about your application to get a consumer key and consumer secret which will be used to identify your application to Fire Eagle.

To create a new app click here (or click the "Create new application" button from the "Developer" home page).

Most of the fields you need to fill in should be fairly self-explanatory. The one interesting bit is "Application Type". For this example we'll choose "Desktop". If your code will someday run on a web server, you'll have to change your application type to "Web". Read more about application types here.

When you submit the new application form, you'll get a consumer key and consumer secret -- jot those down. You can always check them again in the Manage Applications section.

Enough setup. Let's write some code!


Let's Write Code!

You can follow along as we build this application, or you can download the complete finished example app and figure out what's going on for yourself. (The downloadable version contains a few tricks not covered in the example, but should be similar enough...)


Imports and Constants

First we need to do a little code setup. Start off your 'my_app.py' file with the following lines, which basically just set up a bunch of constants we'll use later:


import httplib # used for talking to the Fire Eagle server
import oauth # the lib you downloaded

SERVER = 'fireeagle.yahooapis.com' 

REQUEST_TOKEN_URL = 'https://fireeagle.yahooapis.com/oauth/request_token'
ACCESS_TOKEN_URL = 'https://fireeagle.yahooapis.com/oauth/access_token'
AUTHORIZATION_URL = 'http://fireeagle.yahoo.net/oauth/authorize'
QUERY_API_URL = 'https://fireeagle.yahooapis.com/api/user'
UPDATE_API_URL = 'https://fireeagle.yahooapis.com/api/update'

# key and secret you got from Fire Eagle when registering an application
CONSUMER_KEY = 'xxx'
CONSUMER_SECRET = 'XXXX'
		

Script Structure

We'll add in a little structure -- an entry point which will call our main procedure, test_fireeagle(), and also a couple utility functions. All the code after this step will go into the test_fireeagle() method.

The only thing that's actually interesting here is the fetch_response() function which takes an OAuthRequest object. This OAuthRequest encapsulates a variety of information about the operation you're trying to complete, including the URL you want to access and parameters you pass to the URL. OAuthRequest generates a signature based on URL, parameters and OAuth tokens and then OAuthRequst.to_url() returns a URL containing all this info. fetch_response() hits this URL, then returns a response from the Fire Eagle server. (Look in oauth.py for more details if you're curious about what exactly OAuthRequest does.)

Go ahead and add the following code to my_app.py:


def pause(prompt='hit <ENTER> to continue'):
    return raw_input('\n'+prompt+'\n')

# pass an oauth request to the server (using httplib.connection passed in as param)
# return the response as a string
def fetch_response(oauth_request, connection, debug=True):
    url= oauth_request.to_url()
    connection.request(oauth_request.http_method,url)
    response = connection.getresponse()
    s=response.read()
    if debug:
        print 'requested URL: %s' % url
        print 'server response: %s' % s
    return s

# main routine
def test_fireeagle():
    # setup some variables that we'll use when we actually start doing things
    connection = httplib.HTTPSConnection(SERVER) # a connection we'll re-use a lot
    consumer = oauth.OAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET) # just a place to store consumer key and secret
    signature_method = oauth.OAuthSignatureMethod_HMAC_SHA1() # HMAC_SHA1 is Fire Eagle's preferred hashing method

# app entry point
if __name__ == '__main__':
    test_fireeagle()
    print 'Done.'
		

OAuth Stuff

There are a few steps involved getting an OAuth access token for each of your users. Read about user authorization in Fire Eagle. For full details, read the OAuth spec .

Once you've got an access token, you can store it (associated with your user) and reuse the same token until the user revokes the token (tells Fire Eagle that they don't want to share location with your app any more.)

Storing the access token will be one of the bigger changes from the example as presented to an app that runs on a web server. The example assumes that it runs on a single user machine so can use a single file location to store the token.

On a web server you'd need to associate each access token with a particular user. You could store the token in a cookie, but it would probably be much safer/smarter to store tokens in a database linked to usernames or user IDs.

But overall the concepts (and much of the code) from the example should translate reasonably well to the web...

Get a Request Token

This step is pretty easy, since the OAuth library does almost everything for you. We create a new OAuthRequest (telling it our consumer key and consumer secret and the URL we'll be making the request from and a callback URL - use 'oob' if you don't support callbacks.)

OAuthRequest knows how to generate a signature for this request and has a to_url() method to generate a full URL with all OAuth parameters as HTTP GET parameters (we use to_url() in fetch_response().)

Our fetch_response() method should return a string that OAuthToken can parse. The example doesn't do much error handling -- if the server returns an unexpected response, the script will die when trying to parse the token.

The most likely reason for an unexpected response is something wrong with your consumer key or consumer secret -- double check the Fire Eagle site to make sure you copied them correctly into your code. Of course examining the actual server response should help you figure out what's going on here.

Add the following lines right after the setup code in test_fireeagle():


# get request token
print '* Obtain a request token ...'

# create an oauth request
oauth_request = oauth.OAuthRequest.from_consumer_and_token(consumer, http_url=REQUEST_TOKEN_URL, parameters={'oauth_callback': 'oob'}) 
# the request knows how to generate a signature
oauth_request.sign_request(signature_method, consumer, None) 

# use our fetch_response method to send the request to Fire Eagle
resp=fetch_response(oauth_request, connection) 
print 'Fire Eagle response was: %s' % resp

# if something goes wrong and you get an unexpected response, you'll get an error on this next line
# parse the response into an OAuthToken object
token=oauth.OAuthToken.from_string(resp) 
print 'key: %s' % str(token.key)
print 'secret: %s' % str(token.secret)
		

You should now be able to run this script and get a request token from Fire Eagle. Not too thrilling, but a start...

Have your user(s) authorize your app

Again the code in this step is pretty simple. The main difference to the previous step is that the URL isn't signed with OAuth.

We will generate a URL encoding the request token we obtained in the previous step (note the token parameter when we create the new OAuthRequest). The user (in the example case, the user is you) needs to go to this URL to tell Fire Eagle that it's OK for your sample app to access your location. The script will print a URL that you cut and paste into a web browser linking to a form for you to fill out. When you're done, you'll tell the script that it's OK to continue.

This step would be a little different for a web application. You could directly redirect your users to the AUTHORIZATION_URL (rather than having them copy and paste) and when the user submitted the authorization form, Fire Eagle would direct them back to the oauth_callback url you gave in the previous step.

If your app does not support callbacks, Fire Eagle has no way to contact your app after the user authorizes it, so the script just waits for the user to say they're done.

Once the user has authorized your app, Fire Eagle provides the user with an oauth_verifier in the web page. The script needs the verification code to continue. Ask the user to type in the verification code.

Add the following code after the request token code from the previous step:


# authorize the request token
print '\n* Authorize the request token ...'

# we don't need to sign this request
auth_url="%s?oauth_token=%s" % (AUTHORIZATION_URL, token.key)

# this time we'll print the URL, rather than fetching from it directly
print 'Authorization URL:\n%s' % auth_url
oauth_verifier = raw_input('Please go to the above URL and authorize the app -- Type in the Verification code from the website, when done: ')
		

You can run the script again now to make sure everything still works, but it still doesn't do much...

Exchange the Request Token for an Access Token

Now that the user has authorized our request token, we can exchange it for an access token (and an access token is really what we want since that's what we'll need to access the API).

This step is almost the same as the request token step, except that we pass our current request token as a parameter when creating the new OAuthRequest. You have to provide the oauth_verifier obtained in the previous step to FireEagle, when asking for access token. There are also a few more opportunities for things to go wrong -- the most likely being that the request token was not actually approved before we executed this step...

Add the following after the authorize token code:



# get access token
print '\n* Obtain an access token ...'

# note that the token we're passing to the new OAuthRequest is our current request token
oauth_request = oauth.OAuthRequest.from_consumer_and_token(consumer, token=token, http_url=ACCESS_TOKEN_URL, parameters={'oauth_verifier': oauth_verifier})
oauth_request.sign_request(signature_method, consumer, token)
resp=fetch_response(oauth_request, connection) # use our fetch_response method to send the request to Fire Eagle
print 'Fire Eagle response was: %s' % resp

# now the token we get back is an access token
# parse the response into an OAuthToken object
token=oauth.OAuthToken.from_string(resp) 

print 'key: %s' % str(token.key)
print 'secret: %s' % str(token.secret)

		

Feel free to test the script again, but it's not quite done yet.


Using the Fire Eagle API

Now we're finally able to do something useful. The script will ask the user for a location (try entering an address or city name or something like that) and attempt to update their Fire Eagle location to that address.

We need to tell the OAuthRequest about an additional address parameter so that the address can be included in the signature. But the pattern is the same: create a new OAuthRequest, pass in consumer info, an access token, the URL we want to access, and some additional parameters.

There is one more subtle point here -- Fire Eagle requires us to submit location updates as HTTP POSTs (rather than GETs like we've been using for everything else.) So instead of calling fetch_response() here we do the POST code inline (also note the http_method parameter we pass into the OAuthRequest -- this is used in generating the OAuth signature).

If we wanted to do a query instead of an update we'd do a GET instead of POST and fetch_response() would work just fine...


# access protected resource
print '\n* Access a protected resource ...'

s=pause('enter a location:')
params={}
params['q']=s 

# for updates we must use HTTP POST
# note the http_method='POST' param in the line below
oauth_request = oauth.OAuthRequest.from_consumer_and_token(consumer, http_method='POST', token=token, http_url=UPDATE_API_URL, parameters=params)
oauth_request.sign_request(signature_method, consumer, token)
# get the post data from oauth_request
post_data=oauth_request.to_postdata()

# set headers for POST request
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"} 

print 'POSTing to %s' % UPDATE_API_URL
print 'sending headers: %s' % headers
print 'sending data: %s' % post_data

# do the POST
connection.request('POST', UPDATE_API_URL, oauth_request.to_postdata(), headers) 
print 'Fire Eagle says: %s' % connection.getresponse().read() # print the response
		

For now we won't worry about parsing Fire Eagle's response and we'll just assume that the update worked. The response will indicate an error code and message if it has failed. A success response merely acknowledges that the request was received, not that it was handled correctly. Go check your location on the Fire Eagle website to see if the update worked.


Finishing Up

So you've probably realized by now that it's quite a hassle to go through the process of authorizing a request token every time you run the script. It'd be much more convenient to store an access token once we get one. Check out the full version of the example code for a version that writes access tokens to file.