Building Awesome Facebook tabs with a Horribly Documented API

I built this Facebook tab in 2 days.  The entire template file is 111 lines of code.  2 days is way too long for 111 lines …

You can check out the tab here.

I’ve been playing with the Facebook API for a while, and I’ve never really been satisfied with the final product.  Something about it always seemed incomplete.  There were all kinds of restrictions and all kinds of hacks to break restrictions.  For example, I had a photo gallery inside a Facebook tab that leveraged a Dialog window to display a full size image, thanks to the old Javascript API.  Way cool effect for a photo gallery, but hacked out and not really supported which eventually caused it to break.

I’ve been working on a website for a few months, and I wanted to build something that would extend its reach to Facebook.  I wanted to create something that would really allow people to interact with each other, on Facebook, the way they used to with Apps like SuperPoke.

1) Pick a gift.
2) Pick a friend.
3) DIRECT INTERACTION that all your friends see.

The popularity of App provoked direct interaction between two people on Facebook is something that has really faded, probably due to horrible API documentation, and been replaced by a more pure, unaided post based interaction.  Our solution was to build an App that provided quality content worthy of sharing on Facebook while making it a very simple to share the content with a friend.

Facebook has built in facilities for sharing content with friends.  They used to provide access to some of those facilities in older versions of the API, but have since stripped out access to those facilities and replaced it with a lower level access to Facebook data, effectively moving third party developers closer to the database.  This is very beneficial to developers if they can figure out how to interface with the API, as it not only allows, but forces the developer to build out the full flow of interaction, but unfortunately, often becomes a task of blindly reverse engineering return values and function calls.

Alright, enough bitching about Facebook, lets take a look at the product … and I’ll bitch some more later.

Select a Beer

Our wall is composed of a huge list of beers that you can scroll through.  Step 1 is simply to pick a beer.  When you click on the beer, you are asked to authorize the app, giving access to your basic information (friends list).  After Authorizing the App (you only have to authorize it the first time you use it, it will be stored in your preferences), you will be shown a list of your friends in alphabetical order.  ‘In alphabetical order’ doesn’t seem that impressive, but it’s not built in.  The Graph API uses lazy sorting when it returns the friends list, so it had to be sorted in Javascript by the browser.

Select a Friend

Step 2 is just as simple, click on one of your friends.

Post to Facebook Wall

Step 3: Facebook dialog asking if you want to post the chosen beer to the chosen friends wall.  Type in a description, and click share.  Thats it.  3 clicks and you can share any of the almost 200 beers with any of your 342,000 friends.  Simple enough, right?  Now lets look at the code …

<html>
<head>
<style>
// Put some style info for your div ids and classes here
</style>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js" type="text/javascript"></script>
</head>

In the first block of code we setup a basic HTML layout and load the jquery script from Google’s Servers (Props to Google for hosting a lot of good frameworks for the masses).  The Jquery framework is going to help us with a few things, hiding and showing divs, getting and setting variable values, etc.

<body>
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function() {
FB.init({
appId  : 'YOUR_APP_ID_HERE', //FILL IN YOUR APP ID
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml  : true, // parse XFBML
oauth  : true // enable OAuth 2.0
});
//  FB.Event.subscribe('auth.statusChange', onFacebookStatusChange);
};
(function() {
var e = document.createElement('script');
e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
e.async = true;
document.getElementById('fb-root').appendChild(e);
}());

The above code sets up the body element and uses javascript to load the Facebook Javascript API asynchronously.  Be sure to fill in your App ID or this will fail to load the API and all calls to the API will fail.

function onFacebookInitialLoginStatus(response) {
if (response.status != "connected" || response.authResponse == null) {
facebookLogin();
}
FB.api('/me/friends', function(response) {
var friends1 = response.data;
var friends = friends1.sort(sortByName);
var l = friends.length;
for (var i=0;i<l;i++) {
$('#friends ul').append("<li onclick="personSelected(" + friends[i].id + ");"><img src="https://graph.facebook.com/" + friends[i].id + "/picture/"><p>" + friends[i].name + "</p></li>");
}
$('.beers_image_list').hide();
$('#beers_page_header').hide();
$('#footer').hide();
$('#friends_header').show();
$('.friends_image_list').show();
});
}

The above function is responsible for checking the LoginStatus of the requesting user.  I had to reverse engineer the response object as there is no proper documentation outlining what actually gets returned.  What comes back is a list of friends stored in response.data, but the Graph API uses a lazy sorting method and returns the list without any useful sort performed.  We must therefore implement a method in Javascript to sort the returned list.  This all takes place in the browser instead of on the server.

function sortByName(a, b) {
var x = a.name.toLowerCase();
var y = b.name.toLowerCase();
return((x < y) ? -1 : ((x > y) ? 1 : 0));
}

The above function had to be implemented into the code (and was taken from HERE) to sort the list of friends.

function facebookLogin() {
FB.login(onFacebookInitialLoginStatus);
}

The facebookLogin() function does some stuff FILL IN EXPLAINATION

function shareBeer(selected_beer_img, selected_beer_link, selected_beer_name, selected_beer_brewery, selected_beer_type, selected_beer_locality) {
$('#selected_beer_image').html(selected_beer_img);
$('#selected_beer_link').html(selected_beer_link);
$('#selected_beer_name').html(selected_beer_name);
$('#selected_beer_brewery').html(selected_beer_brewery);
$('#selected_beer_type').html(selected_beer_type);
$('#selected_beer_locality').html(selected_beer_locality);
FB.getLoginStatus(onFacebookInitialLoginStatus);
}

The shareBeer() function is really the heart of what makes our product unique and easy to use.  By utilizing the Jquery framework, we are able to create a simple and easy to use user interface that allows users to perform step 1, Choose a Beer.  The function is fired by an onclick event attached to the <li> object that we will look at a little later in the HTML.  shareBeer() takes a few arguments, all of which are information that will get passed to the final dialog and describe the Beer that someone is going to share.  Because I am not overly familiar with Javascript, and it made debugging extremely easy, I chose to pass the variables from step 1 to step 2 inside of hidden div elements in the HTML.  The divs were hidden with CSS (display:hidden;).

function personSelected(person) {
FB.ui({
method: 'feed',
to: person,
name: $('#selected_beer_name').html(),
link: 'http://nationwidebarcrawl.com/link/',
picture: $('#selected_beer_image').html(),
caption: 'Free. As in Beer.',
description: '<center>Brewery: ' + $('#selected_beer_brewery').html() + '</center><center>Type: ' + $('#selected_beer_type').html() + '</center><center>Locality: ' + $('#selected_beer_locality').html() + '</center>'
}, function(response) {
if (response && response.post_id) {
alert('post published');
} else {
alert('post failed');
}
});
}
</script>

This function is responsible for popping the ‘post to wall’ dialog which is popped by calling the ‘feed’ method of the FB.ui() Graph API function.  We again utilize Jquery to pull the values from the Beer object variables that we set inside of hidden divs.  This function is triggered by an onclick event on the <li> that we will look at later in the HTML.  The onlick event passes the Facebook id of the friend who occupies the clicked <li>.  The FB.ui call utilizes this argument as the ‘to’ value for the call.  If you leave the ‘to’ value blank, the dialog will default to posting to the requesting users feed.  Without this ‘to’ argument, our Facebook App loses its ability to provoke social interaction, and thus, its value to the Facebook community.

The description utilizes the <center> tag to get line breaks in our post.  Currently, Facebook does not allow you to put line breaks in your post description, but wrapping each line inside of a <center></center> tag will display the content on separate lines.

<div id="friends">
<div id="friends_header"></div>
<ul></ul>
</div>
<div id="beers_page_header"><a href="http://nationwidebarcrawl.com/beers/" target="_blank"><img src="/media/images/facebook/beers_button.png" /></a></div>
<ul>
{% for beer in beers %}<li><a href="#" onclick="shareBeer('{{ beer.mainphoto.get_singlebeer_url }}', 'http://nationwidebarcrawl.com/beers/{{ beer.slug }}', '{{ beer }}', '{{ beer.brewery }}', '{{ beer.type }}', '{{ beer.get_locality_display }}');"><img src="{{ beer.mainphoto.get_singlebeer_url }}" /><p>{{ beer }}</p></a></li>{% if forloop.counter|divisibleby:"4" and not forloop.last %}</ul><ul>{% endif %}{% endfor %}
</ul>
<div id="footer"><a href="http://cloudcreativegroup.com/" target="_blank"><img src="/media/images/facebook/footer_logo.png"></a></div>
<div id="selected_beer_image"></div>
<div id="selected_beer_link"></div>
<div id="selected_beer_name"></div>
<div id="selected_beer_brewery"></div>
<div id="selected_beer_type"></div>
<div id="selected_beer_locality"></div>
</body>
</html>

The above HTML generates the entire 3 step process in a single page, embedded inside of a Facebook fan page, utilizing Jquery to require only the initial page load to facilitate the entire 3 step process of sharing a gift with a friend.

AN OPEN CALL TO FACEBOOK

Facebook, love the website.  In fact, it eats up a large amount of my daily time, but we have to have a talk about your API.  You guys have moved at an extremely fast pace over the last couple years, starting out as a College based social network and eventually expanding to encompass the whole world.  During this time, many developers have felt as though you haven’t put enough emphasis on keeping your API documentation up to date (and working for that matter).  I like how you guys have spent a lot of time trying to explain the concepts behind a lot of the inner workings of your API, but honestly, none of the documentation really helped me understand what was going on.

The one thing I think you guys could really improve, and quite easily, would be a full API reference.  If you’re not sure what one of those looks like, take a look at Google Maps API Version 3 reference here: http://code.google.com/apis/maps/documentation/javascript/reference.html

With a fully documented API reference, you will see a lot more quality apps being developed for your platform.

This entry was posted in Facebook and tagged , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *