Ten tips and tricks for writing Facebook Apps

(Only a couple of these are java-specific, but this is a.k.a.: “How to make Facebook Apps using Java – part 3″)

(I assume you’ve already had a look at part 1 and part 2? They’re more beginner-oriented)

Bugs, Misconceptions, and Subtle Features

Interfacing with Facebook’s servers is pretty hard, considering how seemingly trivial the interface is. Obviously the almost total lack of documentation is mostly to blame for this, but some of it is just common bugs that have yet to be fixed.

So, here’s ten things I’ve found whilst fiddling with the API, and some of the nicer features that may not be immediately obvious even if you do read the docs provided by FB (you should go read all of them, but … there’s some bad organization and layout, so it can be a chore reading the mega-long HTML pages, with many of the API features having just blanks for description fields :( ).

#1 – FacebookRestClient.java is broken (bug)

I’ve had a couple of problems with this class, provided by FB themselves, although most of them turned out to be just inconveniences / bad design. This one, however, is clearly a bug, since it’s impossible to use some of the methods in the class until you fix their source code.

NOTE: I’ve done this for you, at the bottom of this page is a link to download a “fixed” version of the source, along with some other useful files. What follows is FYI in case you want to make the change yourself…

In line 103, you need to change:


protected class Pair<N, V> {

to:


public class Pair<N, V> {

Note: without this, you cannot legally create instances of that class from within your own code.

If you cannot create instances of that class, you cannot provide the arguments to the handful of methods that REQUIRE a Pair<N,v> (or a list of them) as one of their arugments.

I’m not sure why the author of the class made this class protected – seems to just be a silly mistake. I imagine they thought that perhaps “it’s an internal hidden class – therefore I must hide it” … but it seems to exist mainly to be one of the REQUIRED arguments to the public methods, so this is obviously wrong. Oh well.

#2 – Callback URL is not a page, it’s a directory

This one is annoyingly subtle – everywhere you use the callback URL, and create canvas pages, this isn’t explained. When you are REQUIRED to invent a URL for this, you’re not told what it really is. Instead you have to dig into the docs to find the following nugget:

If you want to create Facebook Canvas pages, you must specify a directory name for your pages. Directory names are unique so you cannot have a name another app has claimed. Once you specify a directory name, going to http://apps.facebook.com/YOUR_DIRECTORY_NAME/pagex.abc will render pagex.abc from pagex.abc in the Facebook Canvas.

Note: that is CORRECT even though it appears to have a typo – Facebook really does render the page pagex.abc with no slash inserted between the two parts – if you don’t put a slash on the end of your Callback URL when you type it into the Create Application form, you’ll find there’s no slash between the Callback URL and the “pagex.abc”.

Note2: You can, in fact, deliberately request “http://apps.facebook.com/YOUR_DIRECTORY_NAME//pagex.abc” (note the double-slash) to cause FB to insert a slash in the request it sends to your webserver. But I woudl advise against this – it’s the kind of behaviour that’s likely to be removed in the future, since double-slashes are not legal in URL’s IIRC (c.f. the URL/URI RFC’s if you’re interested…), and are usually a sign of attempts to hack a server (so are strongly discouraged).

I’d actually given up on creating canvas pages, and had just moved to doing everything with relative iframe links. This is, apparently, WRONG (and probably explains some of the other inconveniences I’ve had to date).

So, to be entirely clear, here’s the way you should make your Canvas pages (I think!)

  1. When you choose a Callback URL, make sure you type it in with a slash on the end
  2. Each page you want as part of your app you should link to as “[callback URL]/[page name]“
  3. In J2EE, map a servlet (in the simplest case; get more fancy if you prefer using struts etc) onto the directory path
  4. Configure that servlet to handle authentication (see my previous post on how to do facebook authentication)
  5. …and to chain the request to a different servlet by reading the “[page name]” part of the incoming URL

NB: there are various ways of doing that more elegantly in J2EE. I don’t want to start writing a tutorial on J2EE, so I’m not going to go into them – there’s tonnes and tonnes of info and docs on this stuff if you don’t know it yet … google is your friend!

#3 – Facebook apps can ONLY change things when one of their users is in the middle of using Facebook

You CANNOT perform actions with the FB API unless at least one of your app’s users is actively logged in to Facebook AND is using your application.

This is by design, but it has some nasty knock-on effects. Essentially, it seriously limits your ability to interface FB with other applications and networks, because although FB users can have arbitrary effects on external data, external data is forcibly prevented from having any effect on FB.

Example? Well, you can only post to the newsfeed of user X if user X themself is currently using FB *right now* at the moment you want to do the post. That means that you cannot, say, post to someone’s newsfeed (and by extension to all their Friends’ feeds for free) each time “someone visits my MySpace page” or each time “someone rates me a 10 on HotOrNot”.

There are workarounds:

Workaround 1: many of the API actions can legally be peformed for ANY of the “users of your application” if “any” of the other users are actively logged-in. For instance, you can query the friends of one of your users so long as at least one user is logged-in. Assuming your app is popular, there will always be SOMEONE logged-in, and you can piggyback of that logged-in user to refresh other data inside your app that depends upon reading info from facebook.

Workaround 2: In particular, anywhere that you use FBML, you can insert an tag, and for a given fb:ref it is possible – with a single method call – to simultaneously update ALL Facebook pages (every user profile, for instance) that has the fb:ref tag in it.

The way the tag works is that you include something like this:


<fb:ref url="http://yoursite/facebook/profile-FBML" />

inside the FBML you “set” as each user’s profile-FBML for your app.

Sometime later, perhaps once every hour – and only when you have a logged-in user who’s Facebook authToken you’re using! – you call:


// See item #10 on this page for more info!
iFacebookClient.fbml_refreshRefUrl( "http://yoursite/facebook/profile-FBML" )

…and ALL the user profiles will update simultaneously. Allegedly – I haven’t tried this yet myself, I’m only using FBML a very small amount at the moment. I’ll update this as and when I have problems / find solutions / etc :).

NB: this ONLY allows you to update the “common” or shared parts of people’s profiles (or whatever FBML you’re setting) – it doesn’t allow you to update customized FBML for each person.

i.e. you could use it to have a “top 10 leaderboard of all users” that appers in everyone’s profile and updates frequently seemingly automatically, but you could NOT use it to have a “your position on the leaderboard” that updates automatically (you would only be able to update that part for each user when that particular user simultaneously logged-in to your app and to facebook).

However … you can still use workaround #1 to update EVERYONE’s profiles manually, one-by-one, whenever ANYONE is logged-in, because the method call to update an individual profile has an optional argument that lets you specify exactly which profile to update – it doesn’t HAVE to update only the profile of the logged-in user.

#4 – Javascript is not allowed in FBML

Currently, Javascript is not allowed. If you include attributes like onClick, onMouseOver, onKeyUp, etc. we will strip them out.

So, in case you were wondering, *that’s* why your javascript ain’t working…

#5 – CSS is not allowed in FBML (with exceptions)

Referencing external CSS stylesheets is not allowed, but you can use style tags and put your CSS definitions there.

I *think* that’s another typo (argh!) – I think they meant “but you can use style ATTRIBUTES” (i.e. the person writing it didn’t realise that style=”" is an HTML attribute, whereas HTML tags look like this: <span></span>).

i.e. you are NOT allowed to do this:


<head>
< ... stylesheet href="...">

(you’re pointing to the stylesheet on some other website (even your own website) on the internet, using the URL of the stylesheet to tell HTML to pull it in)

…but you ARE allowed to do this:


<span style="border-top: 30px; margin-right: 0; text: #ff0000;">
some formatted text
</span>

So, you’re allowed to “use” CSS within the HTML, but you just aren’t allowed to make your HTML clean, readable, easy to edit, or easy to debug. That sucks. Most people who use CSS will avoid doing “CSS in style attributes” like the plague – it’s messy and horrible and really hard to maintain.

But at least you can actually use CSS, instead of being forced to write 10-years-old HTML from the pre-CSS days.

#6 – The Create-App HTML form (bug)

The create-app page on FB is broken – it periodically saves its data to the live servers, but the data it displays that it THINKS it has saved is not the same as what has ACTUALLY been saved. If you change e.g. your Callback URL, it will APPEAR to change on the settings, but it won’t have changed in real life, but then if you refresh the settings it will APPEAR to have reverted to the old value, but if you “edit” it using the link provided, the value in the textbox will be the NEW value (that it has just claimed it is NOT using).
This is very confusing, and a silly bug, but what it means is: when you change your callback URL, just keep trying refresh on your canvas page URL (apps.fb.com/yourapp) until it finally “works”. Some people have had to wait hours for this to happen, others waited minutes. I found it took around an hour to update.

Also … that whole page is a nightmare. It’s badly explained, it has far too much text, and critically important concepts (like your Callback URL, which is almost the only thing on the whole page you have to fill out, but which – contrary to the instructions! – you HAVE to fill out) are buried deep within it. c.f. Item number 2 above for more info just on the Callback URL alone, info which SHOULD have been embedded in this form.

#7 – Fancy GUI hide/show effects for free

Adding the attributes clicktohide and clicktoshow, you can dynamically hide and show content rendered with FBML

FB even give an example (how nice of them):


<span id="cdc03" style="background: yellow">this can appear and disappear</span>
<input type="submit" clicktohide="cdc03" value="hide"/>
<input type="submit" clicktoshow="cdc03" value="show"/>

#8, #9, and #10 – FacebookRestClient.java is very bad java (bug)

Actually, I got fed up with this crappy class. Problems include:

  1. It’s not an interface
  2. It’s got bugs (c.f. the Pair inner class bug above)
  3. Many methods are 100% undocumented
  4. The class itself is 100% undocumented
  5. Some of the undocumented methods have undocumented REQUIRED ways to call them

So … I took their source code and refactored it.

  1. Get the new interface here (compile all your code against the interface – anything less is just Bad Java Coding)
  2. Get the new “main implementation” here (this is almost 100% the original official FB source code, just refactored a little to fix some nasty design flaws in their use of conflicting method signatures)
  3. Get the new “Pair” class here (used to be contained within the old class with incorrect signature (see the bug above about this), now refactored into separate source file)

Epilogue…

I hope these prove useful to you. If you have any problems, or want more tips on using Facebook, feel free to leave a comment. This is the third post I’ve done on how to write facebook apps, and I’ve got at least one more I want to do yet. If you want to keep up to date with these, add the “facebook” category on this blog to your RSS reader (see also part 1 and part 2)…


16 thoughts on “Ten tips and tricks for writing Facebook Apps

  1. Pingback: T=Machine » How to Make Facebook Apps Using Java - part 2

  2. James Cook

    Whilst I agree that FacebookRestClient.java is pretty bad, you cannot say it is broken just because you don’t like the way they have implemented it.
    My point is that just because ‘Pair’ is protected does not mean it is bugged, you merely have to work around it by extending it:

    public class MyFacebookRestClient extends FacebookRestClient {
    protected Logger log = Logger.getLogger(this.getClass());

    public MyFacebookRestClient(String apiKey, String secret) {
    super(apiKey, secret);
    }

    public void setUserPreference(int key, String value) throws FacebookException, IOException {
    assert (value != null);
    assert (key >= 0 && key (“pref_id”, String.valueOf(key)),
    new Pair(“value”, value));
    }

    public String getUserPreference(int key) throws FacebookException, IOException {
    assert (key >= 0 && key (“pref_id”, String.valueOf(key))));
    log.debug(“Getting user preference: ” + document);
    return document.getRootElement().getTextTrim();
    }

    }

    However, I cannot see a way around having to edit FacebookMethod to get new methods (such as the two above) as you cannot extends Enums, this is poor design.

    The problem you will face when (or if) FB release a new version is that you will have to re-implement your version of the code, whereas by extending it, you wouldn’t.

  3. adam Post author

    Perhaps that was harsher than I intended. I was trying to make it clear that some of the difficulties you face as a user of the API are not your fault, they’re mistakes in the implementation. And that they’re easy to fix if you don’t mind editing the (free, open-source) source.

    My guess is that the code was thrown together fairly quickly, passed basic “Oh, I can write a class that uses this” testing (sure, if you put all your classes into facebook’s package, you’ll be fine), and then they kindly put it up for download. Nothing wrong with that; much preferable to us all having to re-invent the wheel with our own wrappers for the REST calls.

    I see your point on the version/updates issue but I doubt that’s going to be a problem in practice, because Facebook’s real API is the REST one, and the java “API” is really just a simple wrapper to that. Any changes that do happen are just going to be the addition of a new method occasionally, which will take all of a few seconds to add to the improved version.

    OR…there’ll be a whole new API implementation in java, with better separation into multiple classes and interfaces, in which case we’ll all need to rewrite our own interfacing code anyway :).

    Take it or leave it :) if it’s no use to you, that’s fine. For me, I *needed* to refactor this into a proper interface/class separation anyway (I’ve also created a “FakeFacebookClient.java” implementation that fakes the authentication part and makes it easy to test without accidentally doing bad things to the FB servers; using the interface, I can swap this in and out without even having to recompile my code), so I’d already taken the potential (but very small) cost of version updates, and doing some bugfixing at the same time could only be beneficial for me.

  4. aroth

    You may be interested in an open-source project related to fixing/improving the poorly maintained Java Facebook API:

    http://code.google.com/p/facebook-java-api/

    And I agree that having the Pair declared as ‘protected’ essentially means that the API is broken. It makes no sense to have a publicly exposed API call that requires as a parameter a protected data structure. Either the API call should be declared as protected, or the data structure should be declared public.

    And of course, there was also no reason for ‘Pair’ to have been nested inside of FacebookRestClient anyways.

  5. adam Post author

    Thanks, that does look interesting.

    I would definitely join in, except for fact that the overriding aim of the project is to be drop-in compatible with the old facebook API – this seems to me a waste of time. There is too little benefit in carrying on implementing within the strictures of an un-maintained and hacked-together API just for the sake of it.

    If they were willing to make the API cleaner, I’d be right there :).

  6. Guy

    Thanks for the tips and also thanks for the open-source facebook-java-api in:
    The http://code.google.com/p/facebook-java-api/

    I started working with after trying to work with the original jar and it makes all the difference in the world. The POJO approach is making the code much more readable. Not to mention all the bugs that were fixed.

  7. Rabbi

    Recently i have found that FacebookRestClient.notifications_sendRequest() does not exists in the new API.
    i have tried with the notifications_send() ,where the content i sent is

    “Get this fabulous Game? <fb:req-choice url=’http://www.facebook.com/add.php?apikey=” + api_key + “‘ label=’Add The Application’ > ”

    But i dont get anything for the <fb:req-choice ..> tag.

    can anyone help me how can i send invitation from my java code .

    Thanks in advance

  8. anonymouscowherd

    Maybe they meant this kind of thing:

    H1 {border-width: 1; border: solid; text-align: center}

  9. anonymouscowherd

    OK, well the elements didn’t show up.

    The idea was this.

    HEAD>
    STYLE type=”text/css”>
    H1 {border-width: 1; border: solid; text-align: center}
    /STYLE>
    /HEAD>

  10. bob

    anonymouscowherd is right, the documentation really does mean style *tags* are allowed in FBML (style attributes are as well).

  11. Josh

    Adam,

    Keep up the good work! I’ve bookmarked you and passed your site to a few of my colleagues looking to create mashups with Facebook.

    Kudos!

    Josh

  12. david allen

    I am trying to create my first java facebook application. I am trying to retrieve a users albums. The user has albums but the call is always returning null. The getAlbums call takes the user Id. I am getting this by calling getUserId. However, this always returns a question mark.

    I would really appreciate your help. As I am stuck.
    Here is my code

    com.facebook.api.FacebookXmlRestClient authenticatedClient = new com.facebook.api.FacebookXmlRestClient("my_api", "my_secret");
    			authenticatedClient.setIsDesktop(false);
    			authenticatedClient.auth_getSession(authToken);
    			
    			request.getSession().setAttribute( "facebookClient", authenticatedClient );
    			
    			
    			org.w3c.dom.Document document = (org.w3c.dom.Document) authenticatedClient.photos_getAlbums(new java.lang.Integer(authenticatedClient.auth_getUserId(authToken)));
    			org.w3c.dom.NodeList nodes = document.getElementsByTagName("albums");
       		 	org.w3c.dom.Node node = nodes.item(0);
       	 		out.write(node.toString());
    

    I am working on this in a jsp to simply get something working.

  13. Tom Kiss

    I used the tag at the top, no probs.

    No idea about Java but creating a PHP based app was pretty straightforward.

  14. Nirmala Kolura

    Hi,

    This is with reference to “#2 – Callback URL is not a page, it’s a directory”

    Let me how faceBook application will come to know which jsp page it has to call first time or when I click on my canvas URL….. my callback Url directory has 5 jsp pages…

  15. Primož Fideršek

    Hi,

    as I can see you know alot of developing of facebook apps.

    I have a question that havent been answered yet on other sites,
    and official forums.

    Is there any way to retrive, user messages, news feed and wall content.
    Im developing and desktop app, and without this data is my app more likely useless.

    Will be very greatfull for help.
    Regards

  16. shivaramaraju

    Hi All,

    I am using this code to getting album names list.In that i am getting null value of the nodes.item(0);

    Document doc = (Document)client.photos_getAlbums(userId);
    org.w3c.dom.NodeList nodes = doc.getElementsByTagName(“album”);
    org.w3c.dom.Node node = nodes.item(0);
    logger.info(node.toString());

    So please give me your suggession for this

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Current month ye@r day *