17 November 2008
Familiarity with ColdFusion.
One of the more interesting developments in the Internet world we all love and live in has been the rise of social networks. MySpace is the poster child of this (sometimes sordid) group, but it is certainly not the only social network. Facebook is probably second in popularity to MySpace, and has a slightly more mature reputation, although it's not all seriousness for sure. Facebook though has innovated in ways that other social networks have not.
In May of 2004, Facebook revealed a new API (dubbed the Facebook Platform) that dramatically changed the entire face of social networks. By following a specific API, you could now write your own applications, essentially extending and building upon the networks Facebook had already created. This API supports applications written in any server-side language, but why use any language when we have the best available - ColdFusion! This article shows how to create a simple ColdFusion-based Facebook application.
The first and probably most important thing you have to know about working with Facebook is that it is not like other APIs you have worked with in the past. Consider the Yahoo! API (you can find nice ColdFusion wrappers for this API at http://cfyahoo.riaforge.org). The Yahoo! API is a set of URLs that server-side code can use to request a specific set of data and then parse the response. So to get weather for Lafayette, LA, I simply need to have ColdFusion request this URL: http://weather.yahooapis.com/forecastrss?p=70508. This returns an RSS response that is simple to parse with ColdFusion. But notice the order of execution here. The user goes to my site and requests some ColdFusion file. My ColdFusion code does an HTTP call behind the scenes to Yahoo and parses the response. The nicely parsed response is then returned to the user.
Facebook flips this scenario around. Since you are extending the Facebook site, not your own, you end up building code that acts much like Yahoo's service. A user will visit the Facebook site and run your application. Facebook acts like a broker. On the user's behalf it will send an HTTP request to your server. Your server will examine the call and respond accordingly. Facebook will then present the result back to the user.
When your code responds to Facebook, it can include both normal HTML (with some restrictions) and FBML (Facebook Markup Language). FBML includes special tags that Facebook will parse before returning to the user. FBML includes some basic widget and layout support as well as items that will automatically load in user data. Here is a simple example. (Don't worry about the exact syntax for now, I just want you to see an example of what FBML looks like.)
<fb:dashboard> <fb:create-button href="#">Hello world!</fb:create-button> </fb:dashboard>
This creates a simple button within my Facebook page (see Figure 1).
Note that the button is correctly styled to match well with the rest of the site. Here is another example, and again, don't worry so much about the code, but notice the result:
<cfoutput> <p> Hello <fb:name uid="#request.userID#" useyou="false"/>!</p> Here are your friends: <fb:friend-selector uid="#request.userID#" name="uid" idname="friend_sel" /> </cfoutput>
In this example I'm using a
fb:name tag, which displays the name of the user. The second tag,
fb:friend-selector, will create a cool, Ajax-based friend selector. As I type, this selector shows me a list of names that match my search (see Figure 2).
Another piece to the platform is the REST interface. FBML lets you include UI items and widgets easily, and it helps you request other information as well. As an example, the REST interface allows your application to send notifications to the user. It allows the application to work with events. It even allows the application to work with your friends. See the section "Where to go from here" for information on a ColdFusion Component that makes this REST interface very simple to use.
Yet another feature of the platform is FQL, or Facebook Query Language. As you can probably guess, this is an SQL-type interface to Facebook. Here is a simple example:
select name, pic from user where uid IN (SELECT uid2 FROM friend WHERE uid1 = X) and sex = 'Female'
This code will select the name and picture from all the friends of×(this would normally be a Facebook user ID) where the sex is female. You can use FQL via the REST API to perform even more complex interactions with Facebook. There is even more to the platform, but for now, let's get started with a simple application using ColdFusion.
Before you can do anything with the Facebook Platform, you have to be a member of the Facebook network. This is obvious, but just in case you are curious, you will have to have a valid account before you even begin. After you have signed up or logged in, visit the Facebook Developers site. You should definitely bookmark this site as it will be your portal to examples, documentation, and support. Now comes the cool part. In order to create applications for Facebook, you actually use a Facebook application. (I love recursion!) When you visit http://www.facebook.com/developers/ you will see the Developer application. You will be prompted to allow the Developer application to access your information. You must allow this to proceed any further. Once installed, this application is your main tool set to create your own applications. Click the nice, obvious, "Set Up New Application" button to see the form shown in Figure 3.
In this example, I've given it the name HelloWorld, but any name is fine. Don't worry about the optional fields just yet. Select the checkbox to agree to the Facebook Platform terms (after you carefully read them, of course) and then click Submit. You will now see a basic page for your account, like the one shown in Figure 4.
Now that the application is created, you need to edit a few settings so you can begin work on the ColdFusion part of the equation. (Facebook has sample code, but unfortunately for ColdFusion developers, it is written in PHP.) Click Edit Settings. There are two critical settings that you have to worry about. The first is the Callback URL. This is a URL on your server that Facebook will communicate with when running your application. This cannot be a file on your localhost. It must be on a 'real' web server available to the Internet at large. For my test I used: http://www.coldfusionjedi.com/demos/sep09helloworld/.
Note that I have not included the file name. The Callback URL works like a root directory for your application. This allows Facebook to request some other file, like foo.cfm, and proxy the request to the same file on your server. So for example, a request for foo.cfm from within Facebook's hosted version of your application will actually go to http://www.coldfusionjedi.com/demos/sep09helloworld/foo.cfm.
The second important setting is the Canvas Page URL. This is a URL that will be specific throughout Facebook for your application. As you type in the value, the web page will use AJAX to make calls and find out if the value is available. I found this to be a bit flaky and it didn't always accurately return the right message. As you can guess, HelloWorld was already taken, so I used sephelloworld. This means people can visit my application by going to http://apps.facebook.com/sephelloworld.
Save your changes. Now you can try viewing your application at http://apps.facebook.com/<your-application-name>/. Most likely you will see the default Facebook error screen (be ready to see this often!).
Note: If you try to add the application I created in this article, you obviously won't get an error as I have set the application up on the server side.
When I tried viewing http://apps.facebook.com/sephelloworld, the 404 error I received wasn't surprising since I had not actually made the folder yet (see Figure 5). Back on my server, I created that folder and added an index.cfm file with "Hello World!". When I reloaded, I promptly got a 500 error. What is going on now? If you look at the errors using ColdFusion Administrator, you may see something like this:
Again - what does this mean? It turns out this is a side effect of an old feature in ColdFusion.
Years ago, Allaire added a feature to allow for automatic form validation. If you simply named your form fields a certain way, ColdFusion would perform automatic server-side validation. Not many people used the feature, but unfortunately the topic comes up from time to time because there is no way to turn it off! And here is where Facebook application development with ColdFusion hits a big issue. Facebook is doing POST operations that use one of those form fields. ColdFusion won't let you disable the check and you can't tell Facebook to change their API (well you could try, but good luck on that). The solution is to rename your form fields so that ColdFusion won't try to validate them. You can do this by rewriting the form data coming in at the Application.cfc level. For more information, see my post on this topic.
Here is the Application.cfc file I used to implement the fix:
<cfcomponent output="false"> <cfset this.name = "sep09helloworld"> <cfif structKeyExists(form, "FB_SIG")> <cfset form.FB_SIG_FIX = form.FB_SIG> <cfset form.FB_SIG = ''> </cfif> </cfcomponent>
This is a very minimal Application.cfc file. Normally I'd have more methods in here, but I wanted to share the shortest possible fix to the POST issue. Note that it basically takes the form value that's causing the problem (FB_SIG), copies it over, and deletes the old value. Once saved, you can essentially forget about the file and just remember that any Facebook documentation that refers to
FB_SIG will need to be referenced as
FB_SIG_FIX instead. If you've done everything right, when you reload the application in your browser and you should see the Hello World message as shown in Figure 6.
At this point you have a connection between Facebook and your server. You can now start using FBML and the API to enhance your application. Let's make the index.cfm a bit more interesting:
<cfoutput> <fb:tabs> <fb:tab-item href="index.cfm" title="Home" selected="true"/> <fb:tab-item href="about.cfm" title="About" selected="false"/> </fb:tabs> <h3>Hello world</h3> <p> The time is #timeFormat(now(), "short")# </p> </cfoutput>
I've used a bit of FBML here to add some basic navigation. As you can probably guess, this will create a simple tabs-based navigation mechanism. Notice I have simple relative URLs. Again, since Facebook is acting as a proxy, I just need to give addresses that will work off the root callback URL I had set up before. I added one bit of ColdFusion code in there, a time display, just to ensure everything is actually working. I then reloaded the application in my browser (see Figure 7).
Next I added a new file on my server named about.cfm. Since I just want to test the navigation, I used this for the code:
<cfoutput> <fb:tabs> <fb:tab-item href="index.cfm" title="Home" selected="false"/> <fb:tab-item href="about.cfm" title="About" selected="true"/> </fb:tabs> <h3>About</h3> <p> Thanks for visiting the about page. </p> </cfoutput>
Notice that I repeated the tabs but this time set the About page to the selected value. Code like this could easily be abstracted into ColdFusion custom tags to make it easier to provide a layout to your Facebook application.
Jason Delmore shared an interesting, and better, way to handle the POST operation problem discussed earlier in this article. His code handles any and all possible form fields that could accidentally trigger ColdFusion's automatic server-side validation. I didn't include this code earlier, because I wanted to introduce a very quick and simple solution at first. Jason's solution, while more complex, provides an even nicer way to handle the problem. Here is his Application.cfc template:
<cfcomponent output="yes"> <cfset this.name = "sep09helloworld"> <cfset url.form = structnew()/> <cfset structappend(url.form,form)/> <cfset structclear(form)/> <cffunction name="onRequestStart"> <cfset structappend(form,url.form)/> <cfset structdelete(url,"form")/> </cffunction> </cfcomponent>
Notice the following three lines in the "constructor" area of the file (the area that runs on every single request):
<cfset url.form = structnew()/> <cfset structappend(url.form,form)/> <cfset structclear(form)/>
This code creates a new key in the URL scope named form. He appends (that is, he copies) the entire form scope to the URL structure and then clears the entire form. Now look at the
<cfset structappend(form,url.form)/> <cfset structdelete(url,"form")/>
These two lines copy the data back from the URL scope into the Form scope and then remove the key from the URL structure. This seems a bit pointless. The code simply copies data from one struct to another and back. However, this temporary "shift" of data is enough to bypass ColdFusion's server-side validation.
Obviously I have only scratched the surface what you can do on the Facebook Platform; I wanted to focus more on ColdFusion integration than anything else. I encourage you to spend time looking over the Facebook Developer documentation. It will be helpful in building your applications. You may also want to spend time looking at the various options for your application. You can do things based on events (such as a user dropping your application) as well as get very detailed reports. All of this will help improve your application and help it become more popular. (At that point you can start thinking of making money with your application!)
A few developers have graciously shared ColdFusion code that helps new developers build Facebook applications. I encourage you to visit RIAForge and search for Facebook. I have used Dominic Wilson's Facebook FBML Starter Kit. It provides a nice starting template and has a CFC that makes the REST-based API simpler to use.