Posts Tagged ‘pyfacebook’

Facebook apps in Python and Pylons part 2

Saturday, November 22nd, 2008

This article is a followup to my previous post, Facebook apps in Python and Pylons part 1. I’m going to talk a little more about what is interesting about Facebook apps and how they work in practice. At the end, I provide a little code sample and a convenience decorator to save you some hassle.

Why write a Facebook app?

facebook logo

Even if you are pretty familiar with using Facebook, you would be easily forgiven if you didn’t fully understand what the capabilities of a Facebook application are, and how the flow works. Facebook applications essentially offer you:

  • The ability to put your own content on a user’s profile.
  • The ability to update a user’s news feed.

While there are a bunch more things you can do with your Facebook application - as described on the official “Anatomy of a Facebook application” page on developers.facebook.com, those two things are likely the most interesting to you.

How do I add content to the user’s profile and to their news feed?

This is the next question! Obviously, the basic answer is “by writing a Facebook app, stupid!”. Of course, you’re looking for a little bit more than just that. The first step is for the user to add your application. I’m about to drop a whole load of Facebook API jargon - specialised terms are highlighted in bold - the user can do this by visiting your canvas URL. You generate the canvas page from your callback URL, and include some FBML to give it an add to profile button. Once the person adds your application, Facebook will redirect them to your post add URL. From the post add hook, you can use the Facebook API to call setFBML to add content to their profile page, and publishUserAction to add stuff to their feed.

Its pretty trivial - but there is an additional caveat. Before you can do anything useful in a Facebook app, you must have a valid Facebook session. Basically, you want most of your entry points to only be loaded if a user has a logged in session, and if they don’t, you want them to be redirected to the login page. This ends up being a fair bit of boiler-plate code. I have written this method decorator to normalise the boiler-plate code into a single place, such that your Pylons controller methods will be handed a valid PyFacebook API object (from the PyFacebook library - see part 1). Here is an extremely basic code skeleton for a Facebook app in Pylons using my decocorator and PyFacebook:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
def require_login(f):
    ''' This decorator first checks to see
       if the user is authenticated.
       If not, it redirects them
       in the appropriate fashion to the
       log in page.  If they are authenticated,
       it sets up the PyFacebook Facebook
       object and passes it down to our wrapped method. '''
    def redirect(fb, url):
        if fb.in_canvas:
            log.info("doing fbml redirect 302")
            return '<fb:redirect url="%s" />' %(url, )
        else:
            log.info("sending a 302")
            response.status_int = 302
            response.headers['location'] = url
            return 'Moved temporarily'
    api_key = config['pyfacebook.apikey']
    secret_key = config['pyfacebook.secret']
    appid = config['pyfacebook.appid']
    auth_token = request.params.get('auth_token', None)
    fb = Facebook(api_key, secret_key, app_name='myapp',
             callback_path='/myapp/callback',
             auth_token=auth_token)
    if not fb.check_session(request) or not auth_token:
        log.info("got an unauthenticated session request")
        return lambda a: redirect(fb, fb.get_login_url())
    return lambda a: f(a, fb=fb)
 
class FacebookController(BaseController):
 
    def index(self):
        return 'Hello World'
 
    @require_login
    def post_add(self, fb=None):
        fb.auth.getSession()
        log.info("got a valid session from user %s", fb.uid)
        fb.profile.setFBML('<fb:wide></fb:wide>')
 
    @require_login
    def callback(self, fb=None):
        c.uid = fb.uid
        return render('/canvas.fbml')

Hopefully that is enough to get you started. I’ll be writing more about this subject so stay tuned. If you have any specific questions, feel free to post a comment!

Facebook apps in Python and Pylons part 1

Thursday, November 20th, 2008

Recently I have been working on a pretty simple Facebook application. I’ve found that the tough thing about writing a Facebook app is not the app per se, but figuring out what a Facebook app actually is, and how it is supposed to work! Anyway, I’m hoping to shed some light on the subject as I figure it out. This first post is mostly some background and description of the various Python implementations of the Facebook API.

Unfortunately, Facebook’s documentation is pretty bad, with a poorly maintained wiki full of out-of-date and plain misleading information. Also, it is all heavily biased toward PHP. On the one hand, this makes a certain amount of sense, since PHP is a very popular Web scripting language, and Facebook itself is implemented in PHP. However, Facebook apps are fundamentally a HTTP-level construct - that is, Facebook makes HTTP requests of various sorts to your application. HTTP is obviously language independent - any language capable of speaking HTTP can be use to implement a Facebook app. I feel that Facebook should focus more on the system at the HTTP level rather than having a load of PHP code and other examples. Anyway, I digress - what you really care about is writing Facebook apps in Python!

There really two distinct things going on in a Facebook app. One is answering HTTP requests from their servers in a specific way. As I wrote above, any language capable of speaking HTTP can handle this. The second is sending requests back to Facebook, in the form that they expect, with data correctly marshaled and so on. While you could implement this interface yourself, there are existing libraries which do all this marshaling and de-marshaling for you. The two I found for Python were minifb and PyFacebook.

I chose to go with PyFacebook, mostly because it seems actively maintained and has a little more documentation than minifb. The biggest gripe I have with PyFacebook is that it is very Django-centric. The second biggest gripe I have is that it is not very well documented. There is a tutorial on the Facebook wiki which is sadly lacking polish, but its still better than nothing.

The PyFacebook source and documentation talk about some Pylons middleware stuff. I tried to use this but found it to be more hassle than its worth - you can just use their provided Facebook class yourself and avoid some dicking about with middleware.py and so on. Actually all you need if you go this route is their __init__.py file. I dropped this in a subdir named ‘facebook’ in my Pylons lib directory. Then you can just do this to use it in your controller:

1
from intothebin.lib.facebook import Facebook

Then from your callback URL handler, you can do stuff like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def callback(self):
    def redirect(fb, url):
        if fb.in_canvas:
            return '<fb:redirect url="%s" />' %(url, )
        else:
            response.status_int = 302
            response.headers['location'] = url
            return 'Moved temporarily'
    api_key = config['pyfacebook.apikey']
    secret_key = config['pyfacebook.secret']
    appid = config['pyfacebook.appid']
    auth_token = request.params.get('auth_token', None)
    fb = Facebook(api_key, secret_key, app_name='myapp',
            callback_path='/myapp/callback',
            auth_token=auth_token)
    if not fb.check_session(request) or not auth_token:
        log.info("got an unauthenticated session request")
        return redirect(fb, fb.get_login_url())
    fb.auth.getSession()

I’ll talk more about what all this stuff means, and what you actually need to do, in the next post. Stay tuned for more!