1 / 48

OpenSocial Across Containers

OpenSocial Across Containers. Arne Roomann-Kurrik Lane LiaBraaten May 28, 2008. Write Once, Run Anywhere?. Make Your App Robust. Make Your App Robust. Be explicit!. Make Your App Robust. Check for errors!. Make Your App Robust. Check for support!. Robustness - Be Explicit.

urian
Download Presentation

OpenSocial Across Containers

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. OpenSocialAcross Containers • Arne Roomann-Kurrik • Lane LiaBraaten • May 28, 2008

  2. Write Once, Run Anywhere?

  3. Make Your App Robust

  4. Make Your App Robust Be explicit!

  5. Make Your App Robust Check for errors!

  6. Make Your App Robust Check for support!

  7. Robustness - Be Explicit

  8. Robustness - Be Explicit • Spot the bug in this code!  Let's request the owner: • And access their profile URL: function request() { var req = opensocial.newDataRequest(); req.add(req.newFetchPersonRequest(     opensocial.DataRequest.PersonId.VIEWER),      "req"); req.send(response);}; function response(data) { var url = data.get("req").getData().getField(     opensocial.Person.Field.PROFILE_URL)); ...}

  9. Robustness - Be Explicit • On hi5, url is: http://www.hi5.com/friend/profile/     displayProfile.do?userid=XXXXXXXXXX • On orkut, url is: null • The OpenSocial specification only states the following about fields available on Person objects: "The server will always include ID, NAME, and THUMBNAIL_URL."* *http://rurl.org/qoo

  10. Robustness - Be Explicit • Introducing opensocial.DataRequest .PeopleRequestFields.PROFILE_DETAILS • Assign an array of properties you want to access to this optional parameter var params = {}; params[opensocial.DataRequest .PeopleRequestFields.PROFILE_DETAILS] = [    opensocial.Person.Field.ABOUT_ME, opensocial.Person.Field.ADDRESSES, opensocial.Person.Field.AGE ];

  11. Robustness - Be Explicit • Fixing the request: From this... function request() { var req = opensocial.newDataRequest(); req.add(req.newFetchPersonRequest(     opensocial.DataRequest.PersonId.VIEWER),      "req"); req.send(response);};

  12. Robustness - Be Explicit • ...to this: function request() { var req = opensocial.newDataRequest(); var params = {}; params[opensocial.DataRequest.PeopleRequestFields     .PROFILE_DETAILS] = [    opensocial.Person.Field.PROFILE_URL ]; req.add(req.newFetchPersonRequest(     opensocial.DataRequest.PersonId.VIEWER, params),      "req"); req.send(response);};

  13. Robustness - Be Explicit • On hi5, url is: http://www.hi5.com/friend/profile/ displayProfile.do?userid=XXXXXXXXXX • On orkut, url is: http://www.orkut.com/     Profile.aspx?uid=YYYYYYYYY

  14. Robustness - Check For Errors

  15. Robustness - Check For Errors • Why is the following code brittle?  Request a user by ID: function request() { var req = opensocial.newDataRequest(); req.add(req.newFetchPersonRequest(     "14088281537290874435"),     "req"); req.send(response);}; • And get the display name: function response(data) { var name = data.get("req").getData()     .getDisplayName(); ...};

  16. Robustness - Check For Errors • If the passed ID is invalid for any reason, the previous code throws a JavaScript error: data.get("req").getData() has no properties • Check for problems!  All callbacks get arguments withhadErrormethods: function response(data) { if (!data.hadError()) {   var name = data.get("req").getData()       .getDisplayName();   ... }};

  17. Robustness - Check For Errors • Subrequests also have hadError methods: function response(data) { if (!data.hadError()) {   ... } else {  if (data.get("req").hadError()) {   ... } }}; • You can check each request individually to see where the point of error is.

  18. Robustness - Check For Errors • Handling errors gracefully: function response(data) { if (!data.hadError()) {   ... } else if (data.get("req").hadError()) {   alert(data.get("req").getErrorMessage()); } else {   alert("An unknown error occurred"); }}; • getErrorMessage() provides a human-readable error message, but varies by container.  • This may not be ideal for display to an end user.

  19. Robustness - Check For Errors • Check for error types at runtime: function response(data) { if (!data.hadError()) {   ...} else if (data.get("req").hadError()) {   switch (data.get("req").getErrorCode()) {     case opensocial.ResponseItem.Error.BAD_REQUEST:       ...       break;     case opensocial.ResponseItem.Error.INTERNAL_ERROR:       ...       break;   } } else {  ...

  20. Robustness - Check For Errors • opensocial.ResponseItem.Error.BAD_REQUEST • The request was invalid • opensocial.ResponseItem.Error.FORBIDDEN • The gadget can never have access to this data • opensocial.ResponseItem.Error.INTERNAL_ERROR • Server problem • opensocial.ResponseItem.Error.LIMIT_EXCEEDED • Over quota • opensocial.ResponseItem.Error.NOT_IMPLEMENTED • No container support • opensocial.ResponseItem.Error.UNAUTHORIZED • The gadget does not have access to this data

  21. Robustness - Check For Support

  22. Robustness - Check For Support • Containers have different purposes.  Not every field may be available. opensocial.Person.Field.LOOKING_FOR • hi5: not supported • MySpace: not supported • orkut: supported MyOpenSpace.Person.Field.DESIRE_TO_MEET • hi5: not supported • MySpace: supported • orkut: not supported hi5.PersonField.PRESENCE • hi5: supported • MySpace: not supported • orkut: not supported

  23. Robustness - Check For Support • Your impulse may be to write code like this: if (MySpace) {  ...} else if (hi5) {  ...} else if (orkut) {  ...} else { ... } • This is brittle! How do you scale to new containers automatically?

  24. Robustness - Check For Support • Sounds like a job for capabilities querying: var supports_lookingfor =     opensocial.getEnvironment().supportsField(         opensocial.Environment.ObjectType.PERSON,         opensocial.Person.Field.LOOKING_FOR); • Now supports_lookingforhas the following value: • on hi5: false • on MySpace: false • on orkut: true • Goal: Build apps that programatically utilize extra functionality based on such booleans • Why is this approach brittle?

  25. Robustness - Check For Support • Try a container-specific profile field: var supports_desiretomeet =     opensocial.getEnvironment().supportsField(         opensocial.Environment.ObjectType.PERSON,         MyOpenSpace.Person.Field.DESIRE_TO_MEET); • Now supports_desiretomeethas the following value: • on hi5: JavaScript error • on MySpace: true • on orkut: JavaScript error • Oops!

  26. Robustness - Check For Support • What about: var supports_desiretomeet = false; if (MyOpenSpace) { var supports_desiretomeet =      opensocial.getEnvironment().supportsField(          opensocial.Environment.ObjectType.PERSON,          MyOpenSpace.Person.Field.DESIRE_TO_MEET); } • Now supports_desiretomeethas the following value: • on hi5: false • on MySpace: true • on orkut: false • This approach defeats the purpose of querying!

  27. Robustness - Check For Support • You should be able to see that: var supports_desiretomeet = false; if (MyOpenSpace) { var supports_desiretomeet =      opensocial.getEnvironment().supportsField(          opensocial.Environment.ObjectType.PERSON,          MyOpenSpace.Person.Field.DESIRE_TO_MEET); } • Is really the same as: var supports_desiretomeet = (MyOpenSpace) ? true : false;

  28. Robustness - Check For Support • Remember, we don't want to write code like this: if (MyOpenSpace) {  ...} else if (hi5) {  ...} else {  ...} • Apps should query by capability, not container name

  29. Robustness - Check For Support • A workaround is to ignore the enums and go for string representations: var env = opensocial.getEnvironment();var supports_presence = env.supportsField(    opensocial.Environment.ObjectType.PERSON,    "presence");var supports_desiretomeet = env.supportsField(    opensocial.Environment.ObjectType.PERSON,"DESIRE_TO_MEET");var supports_lookingfor = env.supportsField(    opensocial.Environment.ObjectType.PERSON,"lookingFor");

  30. Robustness - Check For Support Wait a sec, isn’t this a worst practice?

  31. Robustness - Check For Support • Thankfully, the specification addresses this issue: “Extra person, activity or other object fields should be defined in an enum under the container's namespace, and the environment should allow applications to discover these fields.”

  32. Robustness - Check For Support • Thankfully, the specification addresses this issue: “For example, if the fieldorkut.PersonField.SPECIAL_FIELDis defined as‘orkut.specialPersonField’, then opensocial.getEnvironment().supportsField(   "person", "orkut.specialPersonField") opensocial.getEnvironment().supportsField(    opensocial.Environment.ObjectType.PERSON,       orkut.PersonField.SPECIAL_FIELD) and should both return true.”* *http://rurl.org/qr4

  33. Robustness - Check For Support • We now have runtime access to capabilities across all containers: • Drawback: Now we have to be sensitive to the underlying string value for Profile field enums

  34. Robustness - Check For Support • Use: • Now, instead of: if (MyOpenSpace) {  ...} else if (hi5) {  ...} else {  ...} if (supports_presence) {  ...} if (supports_desiretomeet) {  ...} if (supports_lookingfor) {  ...}

  35. Container-Specific Extensions

  36. Container-Specific Extensions Hair Extensions Leg Extensions Tax Extensions

  37. Extensions - Discovery • OpenSocial is powerful because containers can add their own functionality. • Add support for photos, videos, new profile fields, custom features, developer tools, etc... • OpenSocial is weak because too many custom extensions leads to code like this: if (MySpace) {  ...} else if (hi5) {  ...} else { ... } • With code like this, why have a standard API in the first place?

  38. Extensions - Discovery • Extensions don’t need to be an all-or-nothing thing. For example, the following code posts an activity with a MediaItem to orkut: var opts = [], items = []; var mediaItem = opensocial.newActivityMediaItem(    opensocial.Activity.MediaItem.Type.IMAGE,     "http://imageurl"); items.push(mediaItem);opts[opensocial.Activity.Field.MEDIA_ITEMS] = items;var activity = opensocial.newActivity(opts);opensocial.requestCreateActivity(    activity,opensocial.CreateActivityPriority.HIGH);

  39. Extensions - Discovery • While the standard OpenSocial specification does not support adding links to these entries, hi5 has implemented an additional call that can attach a link to a media item: mediaItem.setField( hi5.ActivityMediaItemField.LINK, "http://linkurl"); • This call depends on the optional hi5 gadget feature. • You can check for this feature like this: gadgets.util.hasFeature('hi5')

  40. Extensions - Discovery • Now this code posts the same MediaItem to orkut, but also adds a link when running in hi5: var opts = [], items = []; var mediaItem = opensocial.newActivityMediaItem(    opensocial.Activity.MediaItem.Type.IMAGE,     "http://imageurl"); if (gadgets.util.hasFeature('hi5')) {  mediaItem.setField(      hi5.ActivityMediaItemField.LINK, "http://linkurl"); } items.push(mediaItem);opts[opensocial.Activity.Field.MEDIA_ITEMS] = items;var activity = opensocial.newActivity(opts);opensocial.requestCreateActivity(    activity,opensocial.CreateActivityPriority.HIGH);

  41. Extensions - Optional Features • Some features are "nice to have" but aren't always required for core functionality • Example: hi5 allows the definition of “callback” URLs that get pinged whenever a user adds or removes your application. • As a developer, you may find callbacks good for metrics, but not necessary to run the application. • Instead of using <Requires feature=”x”>, OpenSocial allows you to include a feature if it exists on the container using <Optional feature=”x”>.

  42. Extensions - Optional Features • This code pings your server upon add and remove events if the container supports the hi5-lifecycle feature, but continues to work even if the container does not: <?xml version="1.0" encoding="UTF-8" ?><Module>  <ModulePrefs title="Optional features are fun">    <Require feature="opensocial-0.7" />    <Optional feature="hi5-lifecycle">       <Param name="installPingUrl"                   value="http://myserver/install"/>       <Param name="removePingUrl"                value="http://myserver/uninstall"/>     </Optional> </ModulePrefs>  ... </Module>

  43. Extensions - Optional Features • Optional features are a great way for the platform to grow. • Containers are free to innovate and move ahead of the platform, and good ideas are rolled back into the spec. • Example: Lifecycle events are a new OpenSocial feature in version 0.8

  44. Extensions - Common Objects to Extend • DataRequests function request() {  var request = container.newDataRequest();  var photoReq = MyOpenSpace.DataRequest. newFetchPhotosRequest(           opensocial.DataRequest.PersonId.VIEWER);  request.add(photoReq, 'photos');  request.send(response);};

  45. Extensions - Common Objects to Extend • Fields var opt_params = {};opt_params[ opensocial.DataRequest .PeopleRequestFields.PROFILE_DETAILS] = [ MyOpenSpace.Person.Field.MOOD, MyOpenSpace.Person.Field.HEADLINE, MyOpenSpace.Person.Field.DESIRE_TO_MEET ];

  46. Resources • API Reference • orkut & iGoogle • http://code.google.com/apis/opensocial/docs/0.7/reference/http://rurl.org/qra • MySpace • http://developer.myspace.com/community/myspace/myopenspace.aspxhttp://rurl.org/qrb • hi5 • http://www.hi5networks.com/platform/wiki/JsAPIhttp://rurl.org/qrc

More Related