For the first part series of post, click here for Part I.
Writing a Facebook application is in essence the same as writing any web application, only with an additional step where the output from your web app is processed and inserted in to a Facebook page. Although PHP seems the most popular choice (and is what Facebook itself is written in) you can use any of the Python frameworks to write an app. You could even roll your own if you were so inclined. I used Turbogears, but you could easily adapt this to another Framework.
You can generate FBML with any Python templating system. I used Genshi which was quite happy to generate FBML for me as long as it was instructed to produce xml and not html, which you can do by adding format="xml" to the expose decorator. For example, here is the controller method for my stats page.
@expose(template="genshi:microbes.templates.stats", format="xml") def stats(self, *args, **kwargs): num_users = User.select().count() num_added_users = User.select(User.q.added==True).count() num_infections = Infection.select().count() return dict(num_users=num_users, num_added_users=num_added_users, num_infections=num_infections)
To see what that renders, take a look at the source of http://microbes.willmcgugan.com, which is naked FBML (not processed by Facebook).
Adding and Removing Users
The first page that the user requests probably wont be FBML at all. When the user adds your application, then Facebook will redirect to a URL defined in your app settings. If your app needs to store users then this is where you would add the users id to your database. You could then display a welcome page, or simply redirect to one of the pages in your application. Similarly, when a user removes your application the Facebook server requests another. This 'user removed' URL is never actually seen by the user so you don't need to return any meaningful content for it.
Using the Facebook API
For other pages within your application you need to do a little work to retrieve parameters from the page request that allow you to work with the API.
There are two Python modules to help with writing Facebook apps (that I know of). PyFacebook is a complete wrapper for the FB API and may be the obvious choice for writing a new application. However, the documentation was Django centric and I originally wanted to integrate an existing Turbogears application. So I decided to use minifb, which provides the necessary boiler-plate code for making calls to the Facebook API. If I write another application I would probably use PyFacebook to save a little time, but it turns out that doing it the hard way isn't that hard at all.
Before you use any parameters from a Facebook request, they need to be validated with a call to minifb.validate which takes your secret key (supplied by Facebook when you create an application) and a dictionary containing the request parameters. In Turbogears you would simply pass the keyword arguments from the controller method to minifb.validate. When a user has added your app, every call has at least two parameters supplied by the Facebook server; 'user' is the user id of the current user and 'session_key' is a string that identifies the current session which is needed for API calls. In the spirit of removing -- even minimal -- boilerplate I wrote a decorator to add to controller methods which does the validate step and optionally redirects to page if the user is not logged in.
_login_url = "http://apps.facebook.com/virtualmicrobes/" def expose_fb(no_redirect=False): def decorate(f): def func(*args, **kwargs): try: arguments = minifb.validate(FACEBOOK_SECRET_KEY, kwargs) except Exception, e: return str(e) if not no_redirect and "session_key" not in arguments: return '<fb :redirect url="%s" />'%_login_url ret = f(*args, **arguments) return ret func.__dict__.update(f.__dict__) return func return decorate
To use this decorator, just add it before Turbogears @expose decorator, which will make the controller appear just like any other request.
The minifb.call function can be used to make calls to the Facebook API. It takes the name of the API method you want to call, followed by your API key, secret key, session key and any additional parameters required by the method. It sends a POST request to the Facebook server and parses the returned JSON. The return value from minifb.call is a collection of basic Python data types, so it is very easy to work with. Generally API calls will return a list of integers / strings, or possibly a list of dictionaries.
The Facebook server imposes a timeout restriction on pages within your application. From my experiments this seems to be about 7 seconds, if the Facebook server doesn't receive a response from your web app within that time limit it will display 'page not found', or words to that affect. If your server is under strain and you are also making a lot of api calls then it is quite possible to go over the timeout. I initially had this problem, but it turned out to be due to a faulty DNS server which webfaction.com quickly fixed for me. So you may not experience this issue, but if you do I would suggest reducing the number of API calls you make if possible, and if you don't care about the return value of your API calls it would be worthwhile running them in a separate thread. I wrote the following helper function to do just that.
def fire_and_forget(callable, *args, **kwargs): def do_callable(): try: callable(*args, **kwargs) except: pass thread = Thread(target=do_callable) thread.start()
If you wrap an API call with fire_and_forget it will run asynchronously and reduce the time to handle the request.
Hopefully I have convinced you that technology wise, writing a Facebook application is fairly straight-forward. Unfortunately there are other hardships which you will have to face when writing your app. I'll go over them in Part III.