Clojure and the Facebook Graph API

This is my first blog post - it is about my open source project clj-facebook-graph. As you might have guessed already, it is a Clojure library to access the (relatively new) Facebook Graph API. The source code of clj-facebook-graph is hosted on Github and licensed under the EPL, so feel free to extend it and use it as foundation for your own Facebook integration. The comprehensive Facebook Graph API documentation can be found here. Yes, you need a Facebook account to even see this documentation page, otherwise the Graph API examples on this page would not work. Either way, you probably wouldn’t be interested in this blog post, if you haven’t at least a Facebook account ;-) The rest of this blog post is going to show you some examples of how to work with the Facebook Graph API in Clojure and explains the motivation behind the clj-facebook-graph library.

In my humble opinion the (new) Facebook Graph API is a really well designed RESTful API. Most notably the Facebook Graph API excels in its homogenous URL scheme. Each and every resource is accessible by requesting https://graph.facebook.com/RESOURCE-ID and the response is always JSON formatted. Let us take the id of an user for example: https://graph.facebook.com/btaylor With Clojure we can simply slurp the resource content from the URL:

As you can see, the result is a string with a JSON document (here I have formatted the response a little bit, but the ugly escaping of the double quotes of the Clojure REPL is still there, also to point out that the response is a normal String). Here you can use the username “btaylor”, because the user has registered a corresponding Facebook short URL as indicated by the link property of the JSON response document: http://www.facebook.com/btaylor/ Normally you would use the user id here https://graph.facebook.com/220439, which yields the same result. Facebook only shows properties in the JSON response, which are public. If you want to see more properties, you need to be authenticated with a Facebook user account, which must be a friend of the profile owner, too.

So far, so good. However pure JSON cannot be processed easily in Clojure. So let us create a Clojure data structure of the JSON document:

The approach to work only with a plain URL will soon reach its limits. Therefore we should choose a Clojure HTTP library. Here we are going to use clj-http as HTTP Client; it’s based on the Apache HttpComponents Client (the successor of the Apache Commons HTTP Client) and has some pretty cool features. First of all let us repeat the first example with the clj-http client and fetch the profile data of Bret Taylor (id = 220439):

In the above snippet clojure.pprint is only used to format the output for this blog post. The advantage of clj-http here is that it uses almost the same response map format like Ring. In the next step we could extract the :body of the response map to get the JSON document and convert it to a Clojure data structure like in the second example. Certainly this is a little bit redundant, when we do this for each and every JSON response. However clj-http can help us to avoid such boilerplate code through its Ring-style middleware. The clj-http client can be wrapped with this Ring-style middleware. The following code snippet defines a middleware function which automatically converts the JSON response document into a corresponding Clojure data structure:

Regrettably Facebook uses the “text/javascript” mime type instead of the more appropriate “application/json” mime type for all of its JSON REST resources. So this middleware is taylored for this particular Facebook Graph API context. In the next step we can wrap the clj-http client with the wrap-json-response-conversion middleware:

The client/wrap-request is the function of clj-http, which itself wraps the own essential middleware of clj-http around the clj-http.core/request function. We haven’t seen the request function in the examples above, but we used it. The get, post, put and delete functions of clj-http are only syntax sugar for the request function. So for example the clj-http.client/get function is defined as:

With the wrap-json-response-conversion middleware we won’t have to convert a JSON response document manually into a Clojure data structure. It’s simple to add some syntax sugar on top of it again, like the get function for example. Besides the wrap-json-response-conversion middleware the clj-facebook-graph project has several other middleware functions, which offer you more convenience, when you are working with the Facebook Graph API.

If you want to work with the Facebook Graph API the other important part besides doing appropriate HTTP requests is, that you have to provide an integration with the Facebook Graph API authentication mechanism. Basically the Facebook Graph API authentication is an implementation of the OAuth 2.0 standard. Certainly the Facebook OAuth 2.0 implementation is already in the field although the OAuth 2.0 specification is not final at the moment. The Facebook Graph API authentication is documented under: http://developers.facebook.com/docs/authentication/

The clj-facebook-graph library provides some Ring middleware which helps you to integrate the Facebook OAuth 2.0 authentication flow into your favorite Ring-based Clojure web framework. Moreover the clj-facebook-graph includes a full-blown example of how to do this integration with Compojure. The example can be found in the test/clj_facebook_graph/example.clj file. Please clone the clj-facebook-graph project and start your REPLs to follow the upcoming examples. Pay attention that on first-time use you have to invoke “lein compile” to compile the clj_facebook_graph.FacebookGraphException ahead-of-time, otherwise you will get a ClassNotFoundException for this class. After this compile the example.clj and evaluate the following line in the clj-facebook-graph.example namespace:

This starts the example compojure app inside a jetty server. Now you can open your browser and go to: http://localhost:8080/facebook-login

An error?!

If you like to work with the Facebook Graph API, you have to register a Facebook app first, otherwise Facebook won’t let you access its REST resources. This can be accomplished by utilizing the following Facebook website: http://www.facebook.com/developers/apps.php

The most important configuration options here are the “Site URL” and the “Site Domain”. While developing your Facebook app they should be configured for localhost like the screenshot shows. Furthermore the screenshot shows the “Application ID” and the “Application Secret” which are required to do the OAuth 2.0 authentication against the Facebook Graph API. Needless to say that I couldn’t provide the test/clj_facebook_graph/example.clj file with some valid credentials of my Facebook account. The above app was deleted before I have published this blog post and the access data is consequently not valid anymore. So fill in the access data of your own Facebook app to try out the example of clj-facebook-graph. Assuming for this explaination that the above access data would be yours, you need to define the following in the clj-facebook.graph.example namespace:

The example.clj already has a facebook-app-info definition, so you can simply fill in the gaps with your access data. It’s important that you recompile the clj-facebook-graph.example namespace (there is no restart of the jetty servlet container required), even if you just redefine the facebook-app-info on the REPL, otherwise you will still get an error. Now you can go to the Facebook login URL of the example again: http://localhost:8080/facebook-login. You should be redirected to a Facebook login screen (if you are not already logged into Facebook), where you can type in your normal Facebook username and password. After a successful login on this page, Facebook asks every user, if he wants to grant the listed permissions to this application (in this case your app):

The intermediate authorization step only happens once, next time the user will be immediately redirected back to your application. Here comes the redirect-uri into play, in our example we have defined the “http://localhost:8080/facebook-callback” URL as redirect-uri. So after the login (and the authorization in this case of a new user of your Facebook app) the user is redirected to “http://localhost:8080/facebook-callback”, this page should show you a Ring debug response, which simply shows all the contents of the Ring actual request. Please read the Facebook authentication documentation to understand how the OAuth 2.0 authentication works and to get a glimpse what clj-facebook-graph needs to do under the covers. There is one entry left in the facebook-app-info map :permissions, which wasn’t mentioned yet. This vector lists all permissions, which are needed by your Facebook app to operate. You have seen it on the first login and the screenshot above, that Facebook asks the user explicitly, if he wants to grant these permissions to your Facebook app. For further information on this topic please consult the Facebook permissions reference.

So now we are ready to grab some data from the Facebook Graph with the help of the clj-facebook-graph library. First of all make sure you have run through the login procedure described above and have the corresponding REPL at your hand, which is in the clj-facebook-graph.example namespace. The example.clj has some helper functions to make it more convenient to try out something with the Facebook Graph API. Let us see which users currently have done a login via Facebook:

Your full name would highly probable show up here, if you have used your Facebook credentials to login into the example.clj app. Next we can do the first request against the Facebook Graph API and fetch a list of all your friends:

The with-facebook-auth-by-name is only a convenience function of the example.clj. Normally you would have to use the with-facebook-auth macro and provide the access-token directly:

This snippet yields the same result as the snippet before it. The clj-facebook-graph middleware automatically appends the access_token query parameter to the URL and expect that it could be found under the thread-bounded *facebook-auth* variable. The with-facebook-auth macro simply does this binding. It would be very cumbersome to write the full Facebook Graph API URL for each and every request, but thanks to the uniform URL scheme of the Facebook Graph API and a little middleware function of the clj-facebook-graph project, we can use a shortcut for this purpose:

This again yields the same response body. The implementation is completely dynamic so every Facebook Graph API resource is supported, but on the other hand - this approach does no validation at all, if the actual resource URL is valid. The following snippet shows how you can read the entries from your news feed:

I hope you get the idea, so that you are able to simply refer to the Facebook Graph API documentation to do request against the other Facebook Graph API REST resources. clj-facebook-graph has some other middleware on hand to simplify the work with the Facebook Graph API. Furthermore you can still use all of features of clj-http, like query parameters:

The above snippet triggers a clj-http middleware through the use of :query-params, which appends the specified query parameters to the query part of the URL. The limit parameter here instructs the Facebook Graph API to only return two entries at once and to provide a pagination link for the next two entries. The rest are clj-facebook-graph middleware instructions, which will automatically extract the data part of the JSON response as Clojure data structure and hide the pagination mechanism behind a Clojure lazy sequence. The clj-facebook-graph project is only the beginning to create a simple Clojure library to work with the Facebook Graph API. The project is at an early stage and many features are missing, so for example there are no support to write something into the Facebook Graph, besides the plain functionalities of clj-http. So feel free to use clj-facebook-graph as a starting point for your Facebook integration and please contribute the common parts back to the project, which are useful for everyone, who has to work with the Facebook Graph API in Clojure. It’s easy to make other additions to the clj-facebook-graph core like the example.clj illustrates. Besides the with-facebook-auth-by-name function there is another extension, which allows you to display the photo albums of your Friends (or your own) by using their full name instead of looking up the id of the friend:

For this example the permissions “user_photos” and “friends_photos” are requested in the facebook-app-info configuration. I hope you enjoy the tour of clj-facebook-graph and that you may use it as foundation of your Clojure Facebook Graph API integration. If you have any questions, corrections or other feedback than don’t hesitate to contact me or just leave a comment below.

Comments