Tuesday, December 4, 2007

What's wrong with the Facebook API

I've been working with the Facebook developer platform for a few weeks now and have decided to vent some of my opinions about it. I've been heavily interested in Web Services, particularly RESTful ones, lately and have noticed some things about Facebooks "REST" API.
  1. Verbs are important!: For the Facebook API, verbs appear to have no real meaning. A POST can be used inplace of a GET or vice-versa. And PUT and DELETE aren't discussed at all.
  2. Separate Resources are good!: This one makes me real mad...let's say I perform a GET on this URL: http://myserver/user/1821389/friends . What do you think this will do? In my very limited REST knowledge (and a bit of common sense) I would say this will give me all of the friends for user 1821389. Or perhaps I perform a POST on the URL: http://myserver.com/albums with a body containing some sort of "albumTitle"? In either case, it seems obvious what the action will do. Lets take the Facebook "approach" now: POST on http://facebook.com/restserver.php?method=friends.get . What do you think this will do? I did a POST on a generic Resource (restserver.php) and invoked some query for "friends.get". Looking at this without knowing the actual truth, I might think I am adding a new friend to a list of friends for someone (not sure who though). In fact, I'm getting a list of friends for a user.
  3. Inconsistent return formats are bad!: One thing that Facebook does which I think is a good idea is they offer 2 return formats for requests: XML and JSON. Here's a little taste of the same response in different formats:

<friends_get_response xmlns="http://api.facebook.com/1.0/" xsi="http://www.w3.org/2001/XMLSchema-instance" schemalocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd" list="true">
<uid>51824</uid>
<uid>8361861</uid>
...
</friends_get_response>


and

[51824,8361861,...]


I won't go into major details here, but my major issue is with the lack of "tags" or identifiers in the JSON response. I know that JSON is supposed to not be as heavy as XML, but something similar to:

{ friends : [51824,8361861,...] }

Would be a little nicer to work with.

Ah well...I guess you can't have everything in this world.

Friday, November 30, 2007

HttpMethod Delegation in Jersey

I came across a new use case for the JSR 311 (Jersey) implementation. Here's the juicy details:
  • Have a collection resource and a specific resource that is delegated to (ie: UsersResource and UserResource where UsersResource delegates to UserResource if a username is specified)
  • Want to load up a User object for each UserResource so that the duplication is not done and if you request information for a User that doesn't exist, you get an error
  • However, I would like to create a User using the same style (obviously just a different http method)
I was trying to make this happen, but there appears to be something in Jersey that makes it automagically delegate to the specific resource rather than look for an exact match to the method I really want to invoke.

Here's a taste of the code:

UsersResource:
@UriTemplate("{username}")
public UserResource getUser(@UriParam("username") String username) {
User user = RealmManager.instance().getUser(username);
if (null == user) {
throw new WebApplicationException(new RuntimeException("user '" + username + "' does not exist."), 404);
}

return new UserResource(formatterFactory, uriInfo, user);
}


Tried this in UsersResource, but this was not executed:
@UriTemplate("{username}")
@HttpMethod("PUT")
public void addUser(@UriParam("username") String username) {
RealmManager.instance().createUser(username);
}


So there you have it...anyone have any ideas?

ExtJS Default Selection Model for EditorGridPanel

Just doing some playing around with selecting rows in the EditorGridPanel for ExtJS 2 and noticed that the API docs say for the selModel config attribute:
Any subclass of AbstractSelectionModel that will provide the selection model for the grid (defaults to Ext.grid.RowSelectionModel if not specified).

But when I was working away, I found that instead of the RowSelectionModel, I was actually getting a default CellSelectionModel. Any ideas?

Thursday, November 29, 2007

ExtJS 2 and JSR 311 (Jersey)

For a side project at work, I've been working on new UI components using ExtJS and powering this front-end with a JSR 311 (Jersey) back-end.

The other day I was able to get something working for the first time that has troubled me for a bit: dynamic saving of an EditorGridPanel. Basically, the EditorGridPanel gives you inline editing of a table, and then I trigger a save of this data through a REST call back to the server.

The front-end:

function updateUser(e) {
var thisUrl = '
/' + e.record.id;
var f = e.field;
var v = e.value;
var data = { 'field' : f, 'value' : v };
var p = Ext.util.JSON.encode(data);
Ext.Ajax.request({url: thisUrl, method: 'POST', params: p});
}


The back-end:

@HttpMethod("POST")
public void updateField(String body) throws JSONException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
JSONObject o = new JSONObject(body);
PropertyUtils.setSimpleProperty(user, o.getString("field"), o.get("value"));
RealmManager.instance().updateUser(user);
}


As might be obvious, this is to save some details about a user.

One thing I wasn't able to get working was the jsonData option for the Ajax.request call. Jersey would complain about media headers and what not that it couldn't convert into anything.

Facebook Spaminess

There's an interesting little debate going on in the Facebook Developer community regarding "spaminess". Spaminess is a term used to describe how spammy a Facebook application is to non-users.

A little background:

All applications have the ability to hook into the Facebook platform to do many tasks including getting information and posting information about a user (all using a REST interface, that in my opinion is not RESTful). Getting is pretty obvious: give me all the friends of a user, etc. Posting is a little different. You can post news stories, photos, notifications and invitations. The latter 2 are the points of interest.

A notification is a message usually saying something along the lines of "person x did thing y to you". It is almost always a personal message directed at the recipient. It can be sent to both users and non-users of an application.

An invitation is as it sounds...an invite to a non-user to add your application.

So where does spaminess fit in?

Here's the UI from the invite page:


Here's the UI from the notification page (with the little X pressed)


Notice any differences? I sure do, but Facebook doesn't seem to. So spaminess...as you can guess, if a non-app-user hits the little X button on the Notification page for your app, you get a spam marking for your app. If that happens enough your spaminess level rises, and you reach the Blocked status: no notifications will be sent to non-app-users... a.k.a. your app is ruined.

Why not just always send invites to non-users instead of notifications? The short and fun answer is that Facebook recently removed the ability to RESTfully post multiple invitations to users (like you can post multiple notifications to users). Instead, you can provide a button in a form that users can click to send an invitation to a single user.

According to this bug in the Facebook Developer area, Facebook is looking into the problem and will try to fix it. But for many developers, its a little too late. Our Christmas Fun! application has taken a huge hit in growth since this problem started to show up.

Wednesday, November 28, 2007

ExtJS 2 with Accordion Menu

I've been playing around with ExtJS for the last several weeks for a project at my work and just recently went through the process of upgrading out pages from ExtJS 1.x to 2. It was quite the experience and one of things that I found to be much easier was getting the Accordion menu working.

When we used 1.x we used the ux.Accordion menu system. But for 2 I decided to try out the built in Accordion menu.

Here's a taste of some of the code.

Before:
var acc = new Ext.ux.Accordion('acc-ct', {
fitHeight: false,
useShadow: true
})

// create accordian panels from existing DIVs
var panel1 = acc.add(new Ext.ux.InfoPanel('panel-1', {trigger:'title', draggable: true, resizable: true, collapsed:false}));
var panel2 = acc.add(new Ext.ux.InfoPanel('panel-2', {trigger:'title', draggable: true, resizable: true}));
var panel3 = acc.add(new Ext.ux.InfoPanel('panel-3', {trigger:'title', draggable: true, resizable: true}));
var panel4 = acc.add(new Ext.ux.InfoPanel('panel-4', {trigger:'title', draggable: true, resizable: true}));
var panel5 = acc.add(new Ext.ux.InfoPanel('panel-5', {trigger:'title', draggable: true, resizable: true}));
After:
var accordian = new Ext.Panel({
layout: 'accordion',
layoutConfig: {
titleCollapse: false,
animate: true,
fill: false
},
width: 200,
collapsible: true,
items: [
{
title: 'Panel 1',
html: 'Content'
},
{
title: 'Panel 2',
html: 'Content'
},
{
title: 'Panel 3',
html: 'Content'
},
{
title: 'Panel 4',
html: 'Content'
},
{
title: 'Panel 5',
html: 'Content'
}
],
renderTo: 'acc-ct'
});

As you can see, there are slight variations, but I prefer the new approach, even if it is much longer. It works well with ExtJS and their Panel layout which is nice. The only thing I don't like is that I don't know how to get the HTML content from an existing element on the page (like how ux.Accordion will convert DIV tags).

Sunday, November 18, 2007

Facebook Application Reference

For the last few weeks I (along with some friends) have been developing some Facebook applications. Our first release: Christmas Fun! has been fantastic, growing incredibly fast in just the first week and a half. We are working on getting our second app done and are hoping to push it out by the end of the week.

During all this time, we came across a few things that we hope might help other developers:
  • Store Facebook UIDs if you want to do profile updates - there doesn't appear to be a simple way of getting all of the users of your app, so storing them is the easiest way we could find to do mass updates
  • Notifications.send & feed.publishTemplatizedAction - Here's what we found: notifications.send() is basically telling user A that user B did something to them. It also sends an email if configured (an extra parameter). feed.publishTemplatizedAction() is a way of telling all of user A's friends that user A did such-and-such. It also appears to be able to do aggregation of news stories, but we aren't 100% sure. As well, make sure to read the docs on the usage of the tag in the notifications (ie: if you don't place one at the start of your notification, one will be prepended)
  • Images need absolute URLs - or Facebook will yell at you. And make sure the URLs are back to your host and not through Facebook. We recommend having a variable that stores your host in case you ever need to move hosts.
  • Javascript - This is a big one...there's a few things to note here: 1) Facebook proxies your Javascript, so if you get errors using Firebug (or another tool) don't get freaked out if you see "app7291713u1241204901231_foo()" as a function. 2) If your code doesn't work as you thought, double check the FBJS DOM - Facebook likes to give a few different Javascript functions for handling properties.
We'll be sure to add in some more findings as we come across them.

Wednesday, November 14, 2007

Christmas Fun! is Live

After a few weeks of exploration, discovery and heart-ache, we have finally released our first Facebook application: Christmas Fun! This app does 2 main things:
  1. Provides a countdown (to the second) of the time until Christmas
  2. Allows users to send/receive gifts
The whole experience has been educational. We learned about how notifications work (news feeds, profile updates, emails), how FBJS works with code and a few other things.

Within less than a week we had jumped to over 1000 users with over 3000 gifts sent! We are still working away to improve the UI and are coming close to releasing our second Facebook application!

This has also been quite different since we built the entire app in PHP which I have barely used, but have come to appreciate its scripting capabilities.

Tuesday, October 23, 2007

Creating Dynamic DIV tables

While working through making a custom Facebook application (which isn't finished, but will be soon!) I wanted to use a DIV-based layout for my data, rather then the simple TABLE tags. However, it was going to be somewhat dynamic (as in, number of rows would be determined by the data). So here is how I did the creation of the table using JSTL and DIVs. Feel free to enjoy/offer your suggestions.

<div class="div_table">
<c:forEach items="${list}" var="item" varStatus="status">
<c:if test="${status.index % 3 == 0}">
<c:out value="<div style='clear:both;'></div>" escapeXml="false"/>
</c:if>

<div class="div_cell" style="float: left;">
{ put stuff here }
</div>
</c:forEach>
<c:out value="<div style='clear:both;'></div>" escapeXml="false"/>
</div>
The line:
<c:out value="<div style='clear:both;'></div>" escapeXml="false"/>
Basically is like a "new row" signal. In my case, I wanted a 3 column table.

Saturday, October 20, 2007

fb_sig parameters

I've been working away at building my own java library for Facebook applications (Java-Spring-Book) and came across something today that was a little different.

For Facebook API calls, you need to have a session_key as one of your parameters. You get this key by asking for it with authToken. Nothing special here. So, my original plan was to store this session_key so that I didn't have to keep requesting one (and I'm sure many other people would do the same). For simplicity, I decided to store the key in the user's session.

As I started working away, I noticed that I wasn't able to store the key in the session (it was always blank on subsequent calls). Without going into the session more, I decided to try simple http cookies. They may not be the greatest, but they should do the job. Again, they weren't working. Cookies didn't seem to persist across subsequent calls. Strange, no?

From the looks of it, my code was working totally fine. There really wasn't any information in subsequent sessions or cookies. And from what I can tell, that's all by design. Here's my theory as to why:
  • In your application setup, you can tell Facebook whether you want to use FBML or an iFrame to display your content (FBML is a bunch of custom tags that make building apps easier)
  • In order to properly render your page inside of Facebook, a request from the user goes to Facebook to show an app. Facebook then sends a seperate, distinct request to my server to get my content. However, this request is different then the user's request, and appears to be blank each time (no persisted info). The result? No cookies for you!
So how can I go about "storing" a session_key? I don't think I have to. From the looks of it, when Facebook makes a request for my page it appends a bunch of "fb_sig_" parameters (including one for session_key). It looks like I can use these parameters in my calls.

I took a quick look through the Facebook docs and couldn't find anything. Anybody know where this might be at?

Building Custom Facebook Apps

Facebook...what a great thing. Taking a simple idea of friends, Mark has been able to create a company that is probably worth something in the billions. Not bad for someone whose my age. So now that I am in fourth year at UW for Systems Design, my friends and I decided that a design project around Facebook might become profitable (not to mention fun).

Now that Facebook has opened its developer platform up, anyone can make their own applications that users can add to their profile, and for the lucky ones, make a little money. There's even companies (such as Slide) that are based specifically around building custom apps.

Our goal? Well...something that makes something about building apps a little easier. And quite obviously, we have no idea what that something is.

So, now 2 months later, we are well on our way. The 2 other group members are looking at a fairly well-developed PHP library that Facebook provides. They seem to be having a lot of fun and finding it rather simple. And me? Not as much fun. I decided to take the Java approach. And let's just say it hasn't been the most enjoyable or easy experience of my life. But I am learning a lot.

Why isn't it so fun? Well, the Java library Facebook provides is for desktop applications, not web based apps...so some subtlety's cause some problems. But, me, being the try-hard that I am (ha!) has decided to build my own Java library...no small feat mind you.

But I did try something I've never done before (and have been silently inspired by my boss): I've started an open source project around it: Java Spring Book. Right now, it's in a very early stage...I'm still trying to figure out the details. Hopefully, someday it will be in a position to offer some help to new developers (who are like I was when I started).

Monday, February 26, 2007

CGLibbing CGLib

So for my first couple of posts, I figured I would go back and look at some of the many problems I've encountered in my daily life of Java development.

The first problem I came across was trying to CGLib an already CGLibbed object (yea...sounds a little shady to me too).

Anyways, here's the background:
- We use Hibernate (3.1.3 if you want to get specific)
- We wanted the ability to dynamically add getters and setters to objects on the fly (and these getters/setters would actually get/put information from/to another member object)

So, myself and another work colleague set out to see what we could do. First step was to actually figure out how CGLib works. This definately was a little painful since I found the documentation on CGLib to be a little poor (at best!). After a couple hours, we finally got through the basics (read: Enhancer is the class to pay attention to) and were merrily running down our unit testing path.

How far did we actually get? Quite far actually. Dynamic getters/setters? Check. Getters and setters that mapped to other member objects? Check. Being able to save these objects? BOOM!

It seems that Hibernate didn't like what we were doing. What exactly was the problem? The object we were giving Hibernate back was one it couldn't understand. So it threw one of its many exceptions (don't recall the exact one) and we were stuck. But we weren't licked yet! We decided to dive a little deeper...

So how exactly did Hibernate know that the object we were giving it wasn't one it could understand? It appears that Hibernate was calling getClass() and comparing the result against its mapping files. And our CGLibbing process meant that the getClass() wasn't really what we had (I believe it returned the Enhancer class). So further on we trudged!

(Note: The rest of the story is a little hazy at best, so I apologize now)
The short and sweet of the finale is that we investigated modifying the code that did the getClass() calling. I do believe it involved some Hibernate Interceptors, however, we felt we were jumping into a pit of problems (as I usually feel when I start mucking around the code of real professionals). Adding in the fact that we had spent several days trying out variations of our approach with no success, we decided to go back to the drawing board and try again.

So there you have it! Our CGLibbing adventure cut short as we couldn't CGLib and a CGLibbed object. But that doesn't mean its impossible! Does anyone have any success stories? I know I skimmed a bunch of blogs and the CGLib mailing list with no success, but hopefully others have had some.

Up and Running

Alrighty! So this is my first ever blog. Kind of strange seeing as I always have my criticisms of others. Time to see how this will fair.

Stay tuned...