Building social applications with OpenSocial 0.9 JavaScript APIs


The majority of OpenSocial networks implement (or support) version 0.8 or version 0.9 of the specification. While version 1.0 is the upcoming release, version 0.9 will be the main focus of this post as it is the current standard employed by the Yahoo! Application Platform. We will specifically explore the lightweight JavaScript APIs introduced in OpenSocial 0.9, as well as some of the helper methods available.


What Is OpenSocial

OpenSocial is a set of common APIs for working with data from various social networks. The concept behind OpenSocial is to develop once and distribute broadly, meaning that if the OpenSocial specification is used to build out an application, it can be easily and quickly ported to another platform. This concept is important, because when building a social application, you want to reach the largest audience you can. Portability, along with the vast amount of user data that can be pulled, makes OpenSocial an ideal tool for quick and scalable development of social applications.

 

Many networks and companies implement the OpenSocial specification, such as the Yahoo! Application Platform, MySpace, Orkut, and a large number of others. The OpenSocial site offers a full list of networks implementing the OpenSocial specification.


A Few Core Concepts

Before diving further into making OpenSocial JavaScript requests, there are a few core concepts of what we will cover in this spec as well as request methods that should be reviewed.

 

Lightweight JavaScript APIs

With the implementation of OpenSocial 0.9 comes a new set of lightweight JavaScript APIs to help developers by providing simple JSON input/output through simple methods when making data requests to the REST APIs. This new feature significantly reduces the amount of code required to make requests and should reduce ramp-up time for developers. These APIs use a new namespace (osapi) so that the requests will be nicely sandboxed from your older code base.

 

Batching Requests

One of the important aspects to be aware of when making OpenSocial JavaScript requests is request batching. Instead of having to make multiple requests to capture profile information, connection details or updates, a user can tie all of those data fetches into a single AJAX request instead of three. This brings quite a performance boost to your application, for obvious reasons.

 

Additionally, batching requests will ensure that all data is obtained from the request prior to the callback being executed. In Listing 1, we set up a request to capture profile details for the owner of the application (labeled as ownerData) and then another request for the friends of the owner (labeled as ownerFriends).

var batch = osapi.newBatch().
    add("ownerData", osapi.people.getOwner({fields: ['name']})).
    add('ownerFriends', osapi.people.get({userId: '@owner', groupId: '@friends'}));

batch.execute(function(result){
    var ownerName = result.ownerData.name.formatted;
});

Listing 1 – Batching Data Requests

 

We’ll explore these requests in more detail in the following sections.


Capture User Profile Data to Personalize Your Application

Due to the rise of many social networks over the years, one realization about users has become blatantly obvious: the vast majority of people want everyone to know as much about them as they can cram onto their profile. While this is a concern from a privacy and “good sense” perspective, this wealth of knowledge provides the application developer with an extremely large warehouse of data that can be used to personalize applications.

 

This can be anything, from demographically targeting ads, all the way to gender personalization. With all of this information readily available for use, the benefit here is quite clear.

 

Let’s look at this from another angle. One thing that many users have become intolerant of is having to build multiple profiles for every application or social network they use. If you’re using an application on a popular social network like Facebook or MySpace, why would you want to have to type out the exact same information in that application that you’ve already spent a painstaking amount of time entering into your profile? The simple fact is you don’t have to — and that’s why capturing and using the profile information of a user to pre-customize their experience is vital.

 

This task can be accomplished quickly and easily using the getViewer or getOwner methods within OpenSocial (Listing 2).

//opensocial person data request
osapi.people.getViewer({fields: ['name']}).execute(function(result){
    if (!result.error){
        var name = result.name.formatted;
    }
});

Listing 2 – Capturing User Profile Information

 

To create a request to get details about a person, you need to take a few steps (all chained nicely together though). Breaking down the request into its individual parts, we have three distinct sections.

  • osapi.people.getViewer(…) is the method which defines that we want to capture profile information from the viewer. The parameter that we pass into this method is a JSON structure, which defines the fields that we want to return from the profile. In this case, we want to capture the name of the viewer.
  • execute(…) will initialize the viewer data request.
  • the callback, listed as the parameter in the execute function, will be the callback that is hit when the viewer data request completes and will contain the person object returned (result parameter). From this result we can use standard dot notation to get at the data we requested.

 

Every network implements its own list of supported OpenSocial.Person fields, depending on what’s included in their profile system. The full list of OpenSocial 0.9 Person fields is described in the wiki.


Utilize User Connections to Build Your Social Graph

The connections a user creates generally builds out a social graph, which can be used to increase your user base and drive up activity. Connections are a two-way reciprocated link between two users, and when present, means that you are usually able to leverage off profile details of a wider range of people. These concepts work equally well in a follower model such as Twitter; you’re looking for a means of using a physical connection (like a friendship or work tie) to your advantage.

 

Many of us who are present on any of the popular social networks have either participated in (or at least received) annoying status updates from one of the virally popular games such as Mafia Wars, Vampires, or Zombies. Peering into the innards of Mafia Wars, I can see that one of the reasons it has become so virally successful is because of the vast relevant social graph that they’ve built up in their game.

 

The important word here is relevant — something that many networks struggle with at times. Most users of a social platform add many more people other than friends and family — coworkers, the postman, the cousin of the neighbor you say hi to while getting the paper in the morning — and these connections aren’t really what we can call relevant to the user.

 

This means that, for the social container itself, the link between non-relevant users has far less value than one where the users know each other or interact with each other on a regular basis. This same concept is true for your application: When you build the links between the people who use your application, they need to have a way to interact with each other on a regular basis to be of any use to you.

 

Mafia Wars does this by adding your application connections into your “mob,” effectively making them interact with each other in some form whenever they play the game.

 

Much like our previous person request, we can make a simple get request to capture owner friends (Listing 3).

//get owner friends
osapi.people.get({userId: '@owner', groupId: '@friends', count: 10}).execute(function(result){
    if (!result.error){
        var friends = result.list;
        var html = '';
        for (var i = 0; i < friends.length; i++){
            html += friends[i].name.formatted + '';
        }
    }
});

Listing 3 – Capturing User Connections

 

Again, this request can be split up into three individual sections:

  • osapi.people.get(…) is a standard get method that can be used to capture any people data. In this case, we denote within the JSON passed into this function that we would like to capture information from the “owner” of the application where the groupId is “friends”. These are simple strings defining that we would like to capture the owner’s friends.
  • execute(…) will initialize the owner friend data request.
  • the callback, listed as the parameter in the execute function, will be the callback that is hit when the owner friend data request completes and contains all friend person objects for the owner (friends parameter). From this result, we can get the number of friends returned using .totalResults or loop through the list of person objects for each friend.


Promote and Customize Your Application Using Updates

A powerful tool for social application developers is the ability to send updates to the stream of a user. The update stream is the central news area for the user and their connections.

 

Getting Updates

Earlier I mentioned that users will go to great lengths to add in every detail about themselves and their lives into their profiles. What I didn’t mention is that those details might not always be fully accurate, or they may be out of date.

 

The defining truth in any social network is the update stream of the user. When the user sends messages, who they’re contacting, what they’re doing, and what applications they’re using will all become accessible through this stream. This type of request will follow the same syntax as our previous requests but will use the activities API rather than the person API (Listing 4).

//capture viewer activities
osapi.activities.get({userId: '@viewer', count: 20}).execute(function(result){
    if (!result.error){
        var activities = result.list;
        var html = '';

        for (var i = 0; i < activities.length; i++){
            html += 'Activity Title: ' + activities[i].title +
                    'Activity URL: ' + activities[i].url;
        }
    }
});

Listing 4 – Capturing User Activities

 

Within this request we are making a call to osapi.activities.get(...), denoting that we wish to return someone’s activity stream. The JSON object provided as the parameter to this request denotes that we want the activities for a userid that matches that of the current application viewer and we would also like to return only 20 activities.

 

Once this request completes, we can parse through each of the activities and use them however we’d like.

 

For a full list of activity fields defined within the spec, see Opensocial.Activity.

 

Setting Updates

One of the best methods that a developer can use to encourage user growth in an application is to promote the application through the user update stream. Sadly, networks are generally overly saturated with applications, and they sometimes place applications in undesirable locations.

 

The update stream is one of the few prime-time outlets to users that developers still have access to. When a developer taps into this by setting updates that draw in the users attention, they generally see a larger number of users coming to their application. When implementing this in your code, the syntax will look familiar to our previous GET request (Listing 5).

//insert new activity for the current viewer
osapi.activities.create({
    userId: '@viewer',
    activity: {
        title: 'This is my activity',
        url: 'http://www.yahoo.com/'
    }
}).execute();

Listing 5 – Setting User Updates Setup

 

To accomplish the update insert, we make a request to osapi.activities.create(...). As with our other requests, we will pass in a JSON payload defining what we’d like to insert. In the preceding example, we set the userId to viewer to denote that we would like to insert the update for the current application user. Within the activity definition, we create an object which contains the content of the activity. Here we define the title and URL that the title should link to.

 

There are numerous additional fields available for developers to use in order to further customize the update.


The Gadgets API Tool Set

The gadgets API specification within OpenSocial contains a number of helpful utilities to make your development life easier. When building out applications in a container that has heavy restrictions on front-end code, these helper functions will be a lifesaver. Even if the restrictions aren’t there, not having to build out this functionality yourself makes development quicker — no need to reinvent the wheel.

 

AJAX Requests with gadgets.io

One of the helpful utilities under gadgets.io is the makeRequest function for making AJAX requests. When creating social applications, it’s important that the user experience should be as seamless as possible. In this regard, running data requests in the background is an important implementation tactic.

var params = {};
var url = 'http://www.mysite.com/myfile.php';
var callback = callbackFunc;
params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.
io.ContentType.TEXT;
params[gadgets.io.RequestParameters.METHOD] = gadgets.
io.MethodType.GET;
gadgets.io.makeRequest(url, callback, params);
function callbackFunc(response){
   if (response.text){
      //use data returned from server
   }
}

Listing 6 – Making AJAX Requests

 

In the makeRequest method, we define our parameter list to be the type and method of data request that we’re making. We set the content type as “TEXT” and the method as “GET”. The makeRequest call takes in three parameters; the URL to be called, the callback function to call once completed, and the optional parameter list defining what the content / method types are. When the callback is instantiated, we can pull our response object from response.text.

 

The complete gadgets.io spec can be found on OpenSocial gadgets.io.

 

Localization Support with gadgets.Prefs

Another helpful utility within the gadgets spec provides the ability to pull out user localization information for your application using gadgets.Prefs. When building applications, chances are that your app will be seen throughout numerous countries, with numerous languages. Being aware of these details will allow you to better gear your application towards the needs of the viewer.

 

Using gadgets.Prefs, we can pull out the country and language of preference for the user. These two values will go a long way towards customizing your application for your user base (Listing 7).

var prefs = new gadgets.Prefs();
var country = prefs.getCountry();
var language = prefs.getLang();

Listing 7 – Capturing User Localization Information

 

The complete gadgets.Prefs spec can be found on OpenSocial gadgets.Prefs.


Summary

OpenSocial seeks to bridge a large gap, providing common methods for accessing social data on a wide range of networks, allowing developers to build once and distribute broadly. This concept allows a developer to construct an application and deploy it across many supporting networks, providing maximum impact and the most views for a minimal effort.

 

- Jonathan LeBlanc

  • Share/Bookmark


My Proposals at Open Source Bridge 2010


I’m Submitting a Talk to Open Source Bridge – June 1–4, 2010 – Portland, OR

The Open Source Bridge conference will be going on from June 1-4, 2010 in Portland, Oregon. This conference would be a great opportunity to explore open source development and techniques in the industry. Open Source conferences like this are very important for the promotion of open development products and pushing web standards. If you have an opportunity to make it out to this conference I would definitely suggest heading out their way.

 

I’ve submitted two proposals to the conference for this year:

 

- Jonathan LeBlanc

  • Share/Bookmark


Confoo Conference Screencasts and Overview


A few weeks ago I was out in Montreal, Quebec for the Confoo.ca Conference. This conference tied in many technology groups under one roof – PHP Québec, Montréal-Python, Montréal on Rails, W3Qc and OWASP Montréal – all congregating at the Hilton Bonaventure Hotel in downtown Montreal. From what they told us, the conference had: 500 session proposals, 100 speakers, 130 sessions, and 250 visitors over a three-day period.

 

While I was out there I gave a few presentations on some of the great technology coming out of Yahoo. On Friday I ran through a talk on “Browser MVC with YQL and YUI,” highlighting the highly extensible nature of YQL to accept design patterns such as MVC and visualization and controller capabilities built into technologies such as YUI. This is a screencast with the presentation as the audio overlay – if you missed the talk then you can catch it below.

 

The other talk I gave (on Wednesday afternoon) “Foundations of a Social Application Platform”, had to do with some of the core technologies behind social platforms like YAP, MySpace and Facebook. This is a look in from the perspective of a developer and is taken from the years of work we’ve invested in developing applications on many social networks. Below is the screencast from the presentation:

 

During the conference I had a chance to meet up with Asher Snyder (EVP of Technology) and Philip Ross (VP of Engineering) who work on a very interesting PHP Framework called NOLOH (Not One Line Of HTML). Asher ran me through the foundations and functionality behind the makeup of the framework. I can definitely see the potential of NOLOH for server-side engineers who don’t want to deal with the front-end code and functionality of a site or web application. NOLOH integrates a rich set of widgets to rival many of the JavaScript libraries out there . When I asked about the performance of the framework Asher assured me that includes are added in as they are needed, speeding up initial page load. I unfortunately had to miss his talk because it overlapped one of my own but Asher sent by a screencast. One of the other nice pieces of the framework that I saw were the listeners that allow you to tie in a data request for the transport layer. At the end of the screencast Asher ties in flickr photos into his listener but I was thinking of the potential of integrating that with the dynamic data fetching capabilities of YQL. Take a look at “NOLOH PHP Framework – Unified Server Side Development“, and see for yourself.

 

 

Diving into the innards of SQL and the uses of EXPLAIN we had an expert presentation from Sheeri Cabral of Pythian on “Bending Queries to Your Will with EXPLAIN” (A.K.A Optimizing Queries with EXPLAIN). These are some great slides for all you database administrators out there.

 

I can’t dive into all of the talks that were given but if more information is what you’re looking for then take a look at these links:

 

- Jonathan LeBlanc

  • Share/Bookmark


Pushing an Application Update with OpenSocial 0.8


Within the OpenSocial 0.8 specification is a definition available for pushing out a notification to the user stream automatically from an application.

 

What are updates and why should you care?

 

The update (or status) stream of a user is a listing of what they are currently doing or what they have posted for their friends and connections to see. What’s important to note here is that using this stream can drive quite a bit of traffic to your application if you use it. Personally, I never look through the application gallery of a platform like the Yahoo! Application Platform or MySpace. Most of the time I will only ever add applications when I see an app notification through one of the updates produced by one of my friends.

 

I mean – sometimes I just need to find out what Disney princess I am right?

 

In any event, using this update stream is going to push users to your application. This is one of the many tools that we can use to drive more traffic to your application.

 

How does this work?

 

Using standard JavaScript, let’s take a look at the steps that we will need to implement to insert an update. I would suggest that this JavaScript be inserted in a function that is driven by a user event, such as a click action.

var params = {}, activity;
params[opensocial.Activity.Field.TITLE] = "title";
params[opensocial.Activity.Field.URL] = "http://www.myserver.com/index.php";
params[opensocial.Activity.Field.BODY] = "body text";
activity = opensocial.newActivity(params);

First we need to set up the parameters that will define what will be pushed out in this update. In the above example, we assign a title string, the URL that the title string will be linked to and the body (content) of the update. There are a whole series of options available within an activity request that can be added to the above. These are listed on the OpenSocial documentation here: http://wiki.opensocial.org/index.php?title=Opensocial.Activity_%28v0.8%29#Fields. We then call the newActivity() method to define the activity that we want to build. The parameter that needs to be present in the method is the parameter list that we defined right before that request.

opensocial.requestCreateActivity(
	activity,
	opensocial.CreateActivityPriority.LOW,
	callback);

We then call requestCreateActivity to actually send the request and push the update out. There are three parameters present in this method:

  1. activity – The activity we defined in the first code sample
  2. priority – This is the priority that the update should use to send out. This can either be opensocial.CreateActivityPriority.HIGH (or the string ‘HIGH’) or opensocial.CreateActivityPriority.LOW (or the string ‘LOW’). The difference is in whether the user has granted your application permission to push updates out to their stream. If you define a HIGH priority and the user has not granted your application permission to push out updates, the application will attempt to load an authentication flow to allow the user to allow the update out. If you set a LOW priority, if the user has not granted your app permission, the update will be ignored and no authentication flow will be presented.
  3. callback – The function that will be executed when the update is inserted

With a few lines of code, you now have an application that can draw in more users using the update stream.

 

- Jonathan LeBlanc

  • Share/Bookmark


Fetching Viewer Social Data with OpenSocial 0.8


Profile information within a social network (e.g. MySpace, Orkut, YAP, Hi5) is something that users take painstaking amounts of time to input so that they can tell their friends and the world who they are. If a developer is building an application on one of these same platforms, that same profile detail is a gold mine of information that can be obtained to customize and personalize an application. Why would you ever ask a user to input their name, interests or gender if they already have this information freely available on their profile? Having the user re-enter this information is just asking for the user to drop off of your application. Using the knowledge wealth will both decrease user drop rates and make your applicatio more appealing to the masses.

 

Within a container that supports the OpenSocial 0.8 JavaScript specification, fetching the profile information of a person can be accomplished and customized with several steps.


The first thing we do is call newDataRequest to set up a new information request object within OpenSocial. Once this has been done we create our parameter list which will define what type of information we want to access within the information request. In our case here, we specify that we would like to capture “PeopleRequestFields”, namely a user’s “PROFILE_DETAILS”, and of those profile details we want to return the name and the thumbnail_url to their profile image. We can add in a whole series of profile information here, depending on what the container supports within the profile information specification. We then add to our request a newFetchPersonRequest and specify that we want the “VIEWER” profile (this could also be OWNER) and then input the params we set up to define what data we want from the viewer. Then we just name that request as “viewer_profile” so that we can access it later and send the request. The request function takes the name of the callback function as a parameter.


When the request completes and gets to our callback function, our data is returned to us with the profile information of the viewer presuming that everything completed correctly. In the callback we can call get on the returned data, inputting the name of the request, and then call getData on that. If we want a finer granularity of control over the data that is returned, we can then call the getField function with the information that we want (in this case the viewer name).

 

That’s all there is to it – with a few calls you now have all the information you need to personalize your application to every users that uses it.

 

Jonathan LeBlanc

  • Share/Bookmark


OpenSource Bridge – June 17-19th (Portland, OR)


The proposal submission for OpenSource Bridge is over and it’s time to send notes to the organizers for the topics that you would like to see presented at the conference. Please take a moment to look over the proposals and send messages for your favorites. If you are in the area, please contact me and we can meet for some tech talks.

 

I’ve submitted a proposal to discuss “Securing Social with OpenSocial and Caja“, so please take a look at my proposal and vote it up! Here’s an overview of the subject material:

 

In an attempt to integrate standards into the social web, the OpenSocial standards seek to give developers a “build once – deploy everywhere” methodology for engineering applications. With the push to the merging of your real and web world personalities and personal information, the concerns of insecure social habits become very clear.

 

While trying to create easy to develop application environments in a hurry, many OpenSocial containers have gone the route of using insecure iframes as their security models, many times leading to the hijacking of personal information.

 

Caja enters as an open security solution. Providing multiple levels of JavaScript security in an open-source package, Caja delivers what was lacking in the social world – security.

 

This presentation will provide an overview of the Caja security model with OpenSocial standards and explore why security considerations need to be integrated when creating open standards for the social web.

 

– Jonathan LeBlanc

  • Share/Bookmark


Social Networking Application Portability
What We Learned the Hard Way


Our most recent endeavor into social networking applications was to create a full JavaScript driven application on top of a REST web service layer on MySpace, with the intent on having the application portable between multiple OpenSocial compliant containers (e.g. MySpace to YAP, MySpace to Orkut). The web service layer was used to facilitate communication with our MySQL database but all of the application structure and user interactivity was built using JavaScript. We wanted to use the OpenSocial JavaScript API to see what we could do with it, learn more about it and really see what viable options are available over the use of a server side API with regards to portability.

 

Our application was built, published, and ready to move to its next container. We had been switching between Orkut and MySpace on a regular basis during development when either of the containers experienced downtime or decided to push out some new caching initiative that caused us no end of pain. Our next task was to take this new application and push it to YAP (Yahoo! Application Platform). YAP is an OpenSocial 0.8 compliant container that uses Caja to secure user generated JavaScript and libraries. Caja was an initiative that MySpace was going to implement back in April of 2008 but pulled out of. I’ll talk more about Caja in future posts. In any event, we began moving the application over and immediately ran into some issues with the front end JavaScript. Our JavaScript libraries and large portions of our program control JavaScript would not cajole (to make secure JavaScript using Caja).

 

What now?

 

The full client side application was a great experience and we nearly reached the limits on browser capabilities to handle this sort of front end, but now it was time to build the application in a way that would make it portable no matter what container, OpenSocial compliant or not, that we were moving to.

 

So, we replaced a lot of the JavaScript libraries that were generating our dynamic tables, charts, and handling our event streams with strict HTML / CSS, implemented dynamic flash charts which accepted user data as JSON, and moved a lot of our client side code to a server side PHP controller layer. What little JavaScript we had left we module tested against Caja to make sure that all pieces Cajoled properly. We used Smarty to template all of our application states and expanded our web service layer to bundle user and application data into a single callback.

 

Or final application model became a highly portable, modularized, scalable application.

 

Lessons Learned
JavaScript and libraries have their place in programming on their web, and can be used to extend an application in many wonderful ways. When you have complete control over the platform that you are building on, and are building applications without much need for portability, that type of approach usually works in your favor. In the case of social network programming, or any programming done on top of a black box environment, and truly to build portable applications that can be easily deployed over dozens of different containers, this approach has its drawbacks. Flash, server side templates and REST web service layers are just some of the ways we were able to meet the requirements of a portable application. Once we stopped relying on the container & client side compliance and more on our own scalable services, we met all of our goals and were able to port our application.

 

– Jonathan LeBlanc

  • Share/Bookmark


MySpace PHP API – 20 friend maximum return bug fix


While working with the MySpace official and unofficial php api libraries I became frustrated with one slight bug that was causing some pains for my application. I want to note first off that both of these libraries have been great tools to save from having to use the front end javascript api library that OpenSocial defines.

For our needs, we only needed 3 things from the library…the owner profile data, viewer profile data and the owner friend data. The problem here was that no matter what arguments I supplied to the built in functions I could never get back more than 20 friends, even though the standard specifies that it allows for a return of ‘all’ friends and that 20 was just a default. So, I started hacking away at the API and OAuth.php file of the unofficial library to see if I could find a solution.

What was the problem and how was it fixed?
What it looked like is that the OAuth request for friend profile data is temperamental when it comes to the order of the parameters being passed in the query string. It appears that the ‘page_size’ parameter has to be the first parameter passed after the request URI in order for the parameters to have any effect (i.e. http://api.myspace.com/v1/users/{USERID}/friends?page_size=40…). This parameter controls how many user profiles to send back through the request and can be set to ‘all’ for all of your friends’ profiles. So, I went into the OAuth.php file and switched the order that the OAuth and function parameter arrays were being merged. There was a slight issue in the friend request function in the unofficial php api (the array values were not passing correctly to the request function) so I adjusted those features and set up that argument array so that page_size would be the first element passed in to the request.

Where is the fix?
File: http://www.nakedtechnologist.com/files/ms_unofficial_php_api_with_friend_fix.zip

All you need to do is download the zip file, unzip it and replace the unofficial library files. The zip contains all of the files that were in the original API. To do a quick setup to display friend data, you can use the following PHP code:

<?php
require_once(’Space.php’);
$key = ‘http://www.myspace.com/xxxxx’;
$secret = ‘xxxxxxxxxxx’;
$session = new Space($key, $secret);
$friend_list = $session->friends(’USER_ID′,1,’all’);
var_dump($friend_list);
?>

I saw many questions on the forums regarding what the xxxxx portion of the $key parameter is. This is the friend id of your application, which may be viewed on the add application page (e.g. http://www.myspace.com/index.cfm?fuseaction=user.viewprofile&friendid=396659585).

– Jonathan LeBlanc

  • Share/Bookmark