OpenSocial
   Korea - November 2008


Arne Roomann-Kurrik
Developer Relations

Yung Choi
Software Engineer




           ...
Gadgets
Not widgets, not sprockets, not gidgets, not wadgets




                                                       2
Gadgets
A gadget spec:
  • Is an XML file.
  • Defines metadata about an OpenSocial app.
  • Is highly cacheable and does ...
Gadgets
A gadget server:
  • Takes the gadget spec as input.
  • Performs optimizations on the gadget spec.
  • Outputs HT...
Gadgets

A container:
  • Displays the social network’s user interface.
  • Opens an IFrame to the rendered gadget.




  ...
Gadgets
Example gadget XML spec:
 • Uses HTML to print “Hello World”.
 • Colors the text red with CSS.
 • Dynamically adju...
Gadgets

Content sections:
 • Define the current view:

    <?xml version=quot;1.0quot; encoding=quot;UTF-8quot; ?>
    <M...
Gadgets

What are views?
 • Gadgets can render in different locations on a container.
 • Rendering area changes from small...
Gadgets




iGoogle quot;homequot; view:
  • On iGoogle, the quot;homequot; view is a small,
    private page that does no...
Gadgets




          iGoogle quot;canvasquot; view:
            • Large private view, allows ads.


                     ...
Gadgets
Working with views in the gadget XML:
 • <Content> sections are repeated for each view.
 • Add a view=quot;view na...
Gadgets

Add extra features to your gadget:
 • dynamic-height - Change the size of your gadget in the container.
 • views ...
Gadgets



          <?xml version=quot;1.0quot; encoding=quot;UTF-8quot; ?>
          <Module>
            <ModulePrefs t...
Gadgets
Requesting the gadget XML spec:
 1. The client requests an app to be rendered.




                               ...
Gadgets
Requesting the gadget XML spec:
 1. The client requests an app to be rendered.
 2. The container fetches the gadge...
Gadgets
Requesting the gadget XML spec:
 1. The client requests an app to be rendered.
 2. The container fetches the gadge...
Gadgets
Scaling is hard:
 • Easy to start and get some users.




                                       17
Gadgets
Scaling is hard:
 • Being popular on one social network
   can push your server to the limit...




              ...
Gadgets
Scaling is hard:
 • ...being popular on many networks
   can be disastrous.

Caching can help!




               ...
Gadgets
Requesting a cached gadget XML spec:
 1.The client requests an app to be rendered. The container already
   has a ...
Gadgets
Requesting a cached gadget XML spec:
 1.The client requests an app to be rendered. The container already
   has a ...
Gadgets
Requesting a cached gadget XML spec:
  1.The client requests an app to be rendered. The container already
    has ...
Gadgets
Optimizations?
 • Cache, cache, cache.
 • Rewrite links to use content proxies.
 • Rewrite relative links to full ...
The JavaScript APIs




                      24
Gadgets JavaScript

gadgets.* utility functions:
  • gadgets.io.makeRequest()
    Make cross-domain AJAX calls to remote s...
Gadgets JavaScript

gadgets.* utility functions:
  • gadgets.io.makeRequest()
    Make cross-domain AJAX calls to remote s...
Gadgets JavaScript

gadgets.* utility functions:
  • gadgets.io.makeRequest()
    Make cross-domain AJAX calls to remote s...
Gadgets JavaScript

gadgets.* utility functions:
  • gadgets.io.makeRequest()
    Make cross-domain AJAX calls to remote s...
Gadgets JavaScript

gadgets.io.makeRequest():
  • Make cross-domain AJAX calls to remote servers.


Remote content:
 • Wor...
Gadgets JavaScript
Requesting remote content:
 1.The rendered app calls gadgets.io.makeRequest() to fetch
   remote conten...
Gadgets JavaScript
Requesting remote content:
 1.The rendered app calls gadgets.io.makeRequest() to fetch
   remote conten...
Gadgets JavaScript
Requesting remote content:
 1.The rendered app calls gadgets.io.makeRequest() to fetch
   remote conten...
The OpenSocial JavaScript API
Representing users:
 • Client-side, users must work with the VIEWER and the OWNER.




     ...
The OpenSocial JavaScript API
Multiple personalities:
 • When you visit your own profile, you are both the VIEWER and the
...
The OpenSocial JavaScript API
Representing users:
 • Sometimes, containers allow anonymous browsing.


                 ??...
The OpenSocial JavaScript API
 OpenSocial requests:
  • An OpenSocial DataRequest is created.
  • Requests are added to th...
The OpenSocial JavaScript API
 OpenSocial requests:
  • An OpenSocial DataRequest is created.
  • Requests are added to th...
The OpenSocial JavaScript API
OpenSocial responses:
 • Responses are bundled according to the keys specified in the reques...
The OpenSocial JavaScript API
Working with people:
 • opensocial.Person - JavaScript representation of a user.




       ...
The OpenSocial JavaScript API
Request one person:
   req.add(req.newFetchPersonRequest(idspec, opt_params), quot;keyquot;)...
The OpenSocial JavaScript API
Methods available on an OpenSocial Person:

• getDisplayName()
  Gets a text display name fo...
The OpenSocial JavaScript API
 An OpenSocial Person's fields:
• ABOUT_ME         • JOB_INTERESTS         •   SEXUAL_ORIENT...
The OpenSocial JavaScript API
Working with people:
 • A Collection represents many opensocial.Person objects.




        ...
The OpenSocial JavaScript API
IdSpec:
  • idspec is an object that can represent groups of people.
   var idspec = opensoc...
The OpenSocial JavaScript API
Request many people:
   var idspec = opensocial.newIdSpec({
     quot;userIdquot; : quot;OWN...
The OpenSocial JavaScript API
Working with data:
 • Persistent data gives apps key, value storage directly on the containe...
The OpenSocial JavaScript API
Set persistent data:
   req.add(req.newUpdatePersonAppDataRequest(idspec, key, value));

 • ...
The OpenSocial JavaScript API
Fetch persistent data:
   var idspec = opensocial.newIdSpec({
     quot;userIdquot; : quot;O...
The OpenSocial JavaScript API
Fetch persistent data:

 • Data is returned as an object indexed by ID number, then as an ob...
The OpenSocial JavaScript API
Working with activities:
 • API to post information about what users are doing with your app...
The OpenSocial JavaScript API
Post an activity:
   function postActivity(text) {
      var params = {};
      params[opens...
Building apps across containers




                                  52
Challenges

Cross container development is still tricky:
 • Containers may not follow the standard.
 • Containers may foll...
Robustness - Be Explicit

 • Spot the bug in this code!   Let's request the owner:
 function request() {
  var req = opens...
Robustness - Be Explicit

 • On hi5, url is:
       http://www.hi5.com/friend/profile/
           displayProfile.do?userid...
Robustness - Be Explicit

 • Introducing
     opensocial.DataRequest
         .PeopleRequestFields.PROFILE_DETAILS


 • As...
Robustness - Be Explicit

 • Fixing the request: From this...
function request() {
 var req = opensocial.newDataRequest();...
Robustness - Be Explicit

 • ...to this:
function request() {
 var req = opensocial.newDataRequest();
 var params = {};
 p...
Robustness - Be Explicit



 • On hi5, url is:
       http://www.hi5.com/friend/profile/
           displayProfile.do?user...
Robustness - Check For Errors




                                60
Robustness - Check For Errors

 • Why is the following code brittle?   Request a user by ID:
 function request() {
  var r...
Robustness - Check For Errors

 • If the passed ID is invalid for any reason, the previous code throws a
  JavaScript erro...
Robustness - Check For Errors

 • Inside of these DataResponse objects are nested ResponseItem
  objects, which also have ...
Robustness - Check For Errors
 • Handling errors gracefully:
      function response(data) {
       if (!data.hadError()) ...
Robustness - Check For Errors

 • getErrorCode() provides an enum indicating the type of error

      data.get(quot;reqquo...
Robustness - Check For Errors

 • opensocial.ResponseItem.Error.BAD_REQUEST
    • The request was invalid
 • opensocial.Re...
Robustness - Check For Errors

  • Check for error types at runtime:

function response(data) {
 if (!data.hadError()) {
 ...
Robustness - Check For Errors

 • Not all errors need to be fatal!
 • An appropriate response to UNAUTHORIZED would be to ...
Robustness - Off Track For A Second

 • While you can react to an UNAUTHORIZED error, there’s also the
  opensocial.hasPer...
Robustness - Check For Errors

 • Let’s go back to that requestPermission call:

 opensocial.requestPermission(
     [ ope...
Robustness - Check For Errors

  • Unimplemented methods will get an NOT_IMPLEMENTED error
   code:
function callback(data...
Robustness - Check For Errors

 • A container may not implement any method and still remain spec
  compliant as long as th...
Robustness - Check For Support




                                 73
Robustness - Check For Support

 • Containers have different purposes.   Not every field may be
  available.

 opensocial....
Robustness - Check For Support

 • Your impulse may be to write code like this:
if (MySpace) {
  ...
} else if (hi5) {
  ....
Robustness - Check For Support

 • Sounds like a job for capabilities querying:
var supports_lookingfor =
    opensocial.g...
Robustness - Check For Support

 • Try a container-specific profile field:
var supports_desiretomeet =
    opensocial.getE...
Robustness - Check For Support

 • What about:
var supports_desiretomeet = false;
if (MyOpenSpace) {
  var supports_desire...
Robustness - Check For Support

 • You should be able to see that:
var supports_desiretomeet = false;
if (MyOpenSpace) {
 ...
Robustness - Check For Support

 • Remember, we don't want to write code like this:
if (MyOpenSpace) {
  ...
} else if (hi...
Robustness - Check For Support

 • Don't do this:

var env = opensocial.getEnvironment();
var supports_presence = env.supp...
Robustness - Check For Support

 • A workaround is to ignore the enums and go for string
  representations:

var env = ope...
Robustness - Check For Support




          Wait a sec, isn’t this a worst practice?




                                ...
Robustness - Check For Support

 • Thankfully, the specification addresses this issue:




   “Extra person, activity or o...
Robustness - Check For Support

 • Thankfully, the specification addresses this issue:

 “For example, if the field orkut....
Robustness - Check For Support

 • We now have runtime access to capabilities across all containers:

                    ...
Robustness - Check For Support

 • Now, instead of:       • Use:


if (MyOpenSpace) {        if (supports_presence) {
  .....
Resources / Questions?




                         88
Resources

•   OpenSocial Tutorial: http://rurl.org/ss3

•   OpenSocial Spec, Foundation, Reference: http://opensocial.org...
Hacking!
Beginner (http://is.gd/7W05):
 • Write a gadget to display quot;Hello Worldquot; in your favorite container.
 • D...
Upcoming SlideShare
Loading in...5
×

Open Social Summit Korea

2,528

Published on

Slides from my presentation at the OpenSocial Summit in Seoul, Korea, on November 18th, 2008

Published in: Technology, Business
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,528
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
49
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Open Social Summit Korea

  1. 1. OpenSocial Korea - November 2008 Arne Roomann-Kurrik Developer Relations Yung Choi Software Engineer 1
  2. 2. Gadgets Not widgets, not sprockets, not gidgets, not wadgets 2
  3. 3. Gadgets A gadget spec: • Is an XML file. • Defines metadata about an OpenSocial app. • Is highly cacheable and does not need a high performance server. Gadgets use existing web standards • XML to define metadata. • HTML for markup. • JavaScript for interactivity. • CSS for presentation. 3
  4. 4. Gadgets A gadget server: • Takes the gadget spec as input. • Performs optimizations on the gadget spec. • Outputs HTML, JavaScript, and CSS as one document. 4
  5. 5. Gadgets A container: • Displays the social network’s user interface. • Opens an IFrame to the rendered gadget. 5
  6. 6. Gadgets Example gadget XML spec: • Uses HTML to print “Hello World”. • Colors the text red with CSS. • Dynamically adjusts the height of the gadget with JavaScript. <?xml version=quot;1.0quot; encoding=quot;UTF-8quot; ?> <Module> <ModulePrefs title=quot;Hello World!quot;> <Require feature=quot;dynamic-heightquot; /> </ModulePrefs> <Content type=quot;htmlquot;> <![CDATA[ <h1>Hello World</h1> <style type=quot;text/cssquot;> h1 { color: #dd0000; } </style> <script type=quot;text/javascriptquot;> gadgets.window.adjustHeight(); </script> ]]> </Content> </Module> 6
  7. 7. Gadgets Content sections: • Define the current view: <?xml version=quot;1.0quot; encoding=quot;UTF-8quot; ?> <Module> <ModulePrefs title=quot;Hello World!quot;> <Require feature=quot;dynamic-heightquot; /> </ModulePrefs> <Content type=quot;htmlquot; view=quot;canvasquot;> <![CDATA[ <h1>Hello World</h1> <style type=quot;text/cssquot;> h1 { color: #dd0000; } </style> <script type=quot;text/javascriptquot;> gadgets.window.adjustHeight(); </script> ]]> </Content> </Module> 7
  8. 8. Gadgets What are views? • Gadgets can render in different locations on a container. • Rendering area changes from small to large. • Certain pages might be public, some are private. • Containers may have different policies depending on the page, especially when the gadget displays ads. • Views provide a way for gadgets to provide different functionality depending on where it is rendered. 8
  9. 9. Gadgets iGoogle quot;homequot; view: • On iGoogle, the quot;homequot; view is a small, private page that does not allow ads. 9
  10. 10. Gadgets iGoogle quot;canvasquot; view: • Large private view, allows ads. 10
  11. 11. Gadgets Working with views in the gadget XML: • <Content> sections are repeated for each view. • Add a view=quot;view namequot; attribute to each section. • Content sections may support multiple views, for example view=quot;home,canvasquot; <?xml version=quot;1.0quot; encoding=quot;UTF-8quot; ?> <Module> <ModulePrefs title=quot;Hello World!quot;> <Require feature=quot;dynamic-heightquot; /> </ModulePrefs> <Content type=quot;htmlquot; view=quot;homequot;> <![CDATA[ ... ]]> </Content> <Content type=quot;htmlquot; view=quot;canvasquot;> <![CDATA[ ... ]]> </Content> </Module> 11
  12. 12. Gadgets Add extra features to your gadget: • dynamic-height - Change the size of your gadget in the container. • views - Navigate between different surfaces of the container. • skins - Make your gadget change its styles to match the container. • Containers may offer custom features... <?xml version=quot;1.0quot; encoding=quot;UTF-8quot; ?> <Module> <ModulePrefs title=quot;Hello World!quot;> <Require feature=quot;dynamic-heightquot; /> </ModulePrefs> <Content type=quot;htmlquot;> <![CDATA[ ... ]]> </Content> </Module> 12
  13. 13. Gadgets <?xml version=quot;1.0quot; encoding=quot;UTF-8quot; ?> <Module> <ModulePrefs title=quot;Hello Social!quot;> <Require feature=quot;opensocial-0.8quot; /> </ModulePrefs> <Content type=quot;htmlquot;> <![CDATA[ ... ]]> </Content> </Module> The OpenSocial JavaScript API is a gadget feature, too! 13
  14. 14. Gadgets Requesting the gadget XML spec: 1. The client requests an app to be rendered. 14
  15. 15. Gadgets Requesting the gadget XML spec: 1. The client requests an app to be rendered. 2. The container fetches the gadget XML spec from its host. 15
  16. 16. Gadgets Requesting the gadget XML spec: 1. The client requests an app to be rendered. 2. The container fetches the gadget XML spec from its host. 3. The container renders the gadget into HTML, which is displayed to the client. 16
  17. 17. Gadgets Scaling is hard: • Easy to start and get some users. 17
  18. 18. Gadgets Scaling is hard: • Being popular on one social network can push your server to the limit... 18
  19. 19. Gadgets Scaling is hard: • ...being popular on many networks can be disastrous. Caching can help! 19
  20. 20. Gadgets Requesting a cached gadget XML spec: 1.The client requests an app to be rendered. The container already has a copy of the spec stored in its cache. 20
  21. 21. Gadgets Requesting a cached gadget XML spec: 1.The client requests an app to be rendered. The container already has a copy of the spec stored in its cache. 2.The container renders the gadget into HTML, which is displayed to the client. 21
  22. 22. Gadgets Requesting a cached gadget XML spec: 1.The client requests an app to be rendered. The container already has a copy of the spec stored in its cache. 2.The container renders the gadget into HTML, which is displayed to the client. Your server does not even get a request! 22
  23. 23. Gadgets Optimizations? • Cache, cache, cache. • Rewrite links to use content proxies. • Rewrite relative links to full paths. • Concatenate JS and CSS. • Return only content for the current view. 23
  24. 24. The JavaScript APIs 24
  25. 25. Gadgets JavaScript gadgets.* utility functions: • gadgets.io.makeRequest() Make cross-domain AJAX calls to remote servers. 25
  26. 26. Gadgets JavaScript gadgets.* utility functions: • gadgets.io.makeRequest() Make cross-domain AJAX calls to remote servers. • gadgets.json.parse() and gadgets.json.stringify() Native JSON support. 26
  27. 27. Gadgets JavaScript gadgets.* utility functions: • gadgets.io.makeRequest() Make cross-domain AJAX calls to remote servers. • gadgets.json.parse() and gadgets.json.stringify() Native JSON support. • gadgets.util.escapeString() Make text safe for display via innerHTML. 27
  28. 28. Gadgets JavaScript gadgets.* utility functions: • gadgets.io.makeRequest() Make cross-domain AJAX calls to remote servers. • gadgets.json.parse() and gadgets.json.stringify() Native JSON support. • gadgets.util.escapeString() Make text safe for display via innerHTML. • gadgets.util.registerOnLoadHandler() Execute code when the page is finished loading. 28
  29. 29. Gadgets JavaScript gadgets.io.makeRequest(): • Make cross-domain AJAX calls to remote servers. Remote content: • Work with different servers. • AJAX is not cross-domain! • JSONP is only one-way. • Data needs to be cached for millions of users. 29
  30. 30. Gadgets JavaScript Requesting remote content: 1.The rendered app calls gadgets.io.makeRequest() to fetch remote content. 30
  31. 31. Gadgets JavaScript Requesting remote content: 1.The rendered app calls gadgets.io.makeRequest() to fetch remote content. 2.The container requests content from the specified URL. 31
  32. 32. Gadgets JavaScript Requesting remote content: 1.The rendered app calls gadgets.io.makeRequest() to fetch remote content. 2.The container requests content from the specified URL. 3.The container returns the response to the application, which renders the data. 32
  33. 33. The OpenSocial JavaScript API Representing users: • Client-side, users must work with the VIEWER and the OWNER. 33
  34. 34. The OpenSocial JavaScript API Multiple personalities: • When you visit your own profile, you are both the VIEWER and the OWNER. 34
  35. 35. The OpenSocial JavaScript API Representing users: • Sometimes, containers allow anonymous browsing. ?? 35
  36. 36. The OpenSocial JavaScript API OpenSocial requests: • An OpenSocial DataRequest is created. • Requests are added to the DataRequest. • The DataRequest is sent to the server asynchronously. • When the request finishes, the supplied callback will be called. function request() { var req = opensocial.newDataRequest(); req.add(...); ... req.send(response); }; function response(data) { ... }; gadgets.util.registerOnLoadHandler(request); 36
  37. 37. The OpenSocial JavaScript API OpenSocial requests: • An OpenSocial DataRequest is created. • Requests are added to the DataRequest. • The DataRequest is sent to the server asynchronously. • When the request finishes, the supplied callback will be called. function request() { var req = opensocial.newDataRequest(); req.add(req.newFetchPersonRequest(quot;OWNERquot;), quot;get_ownerquot;); req.add(req.newFetchPersonRequest(quot;VIEWERquot;), quot;get_viewerquot;); req.add(req.newFetchActivitiesRequest(quot;VIEWERquot;), quot;vactivitiesquot;); req.add(req.newFetchPersonAppDataRequest(quot;OWNERquot;, quot;*quot;), quot;odataquot;); ... req.send(response); }; function response(data) { ... }; gadgets.util.registerOnLoadHandler(request); 37
  38. 38. The OpenSocial JavaScript API OpenSocial responses: • Responses are bundled according to the keys specified in the request. • Check for an error at the global response level. • Check for an error at the specific response level. • Use getData() to retrieve the actual information in a request. function response(data) { if (data.hadError()) { if (data.get(quot;get_ownerquot;).hadError()) { ... } if (data.get(quot;get_viewerquot;).hadError()) { ... } ... } var owner = data.get(quot;get_ownerquot;).getData(); var viewer = data.get(quot;get_viewerquot;).getData(); }; 38
  39. 39. The OpenSocial JavaScript API Working with people: • opensocial.Person - JavaScript representation of a user. 39
  40. 40. The OpenSocial JavaScript API Request one person: req.add(req.newFetchPersonRequest(idspec, opt_params), quot;keyquot;); • idspec can be either “VIEWER”, “OWNER” or an ID number. • opt_params contains extra request parameters, such as which profile fields to fetch. newFetchPersonRequest responses: var owner = data.get(quot;keyquot;).getData(); alert(owner.getDisplayName()); • Data contains a single opensocial.Person object. • Person objects can contain lots of information, such as addresses, companies, phone numbers, favorite movies, and thumbnail urls. 40
  41. 41. The OpenSocial JavaScript API Methods available on an OpenSocial Person: • getDisplayName() Gets a text display name for this person; guaranteed to return a useful string. • getField(key, opt_params) Gets data for this person that is associated with the specified key. • getId() Gets an ID that can be permanently associated with this person. • isOwner() Returns true if this person object represents the owner of the current page. • isViewer() Returns true if this person object represents the currently logged in user. 41
  42. 42. The OpenSocial JavaScript API An OpenSocial Person's fields: • ABOUT_ME • JOB_INTERESTS • SEXUAL_ORIENTATION • ACTIVITIES • JOBS • SMOKER • ADDRESSES • LANGUAGES_SPOKEN • SPORTS • AGE • LIVING_ARRANGEMENT • STATUS • BODY_TYPE • LOOKING_FOR • TAGS • BOOKS • MOVIES • THUMBNAIL_URL • CARS • MUSIC • TIME_ZONE • CHILDREN • NAME • TURN_OFFS • CURRENT_LOCATION • NETWORK_PRESENCE • TURN_ONS • DATE_OF_BIRTH • NICKNAME • TV_SHOWS • DRINKER • PETS • URLS • EMAILS • PHONE_NUMBERS • ETHNICITY • POLITICAL_VIEWS • FASHION • PROFILE_SONG • FOOD • PROFILE_URL • GENDER • PROFILE_VIDEO • HAPPIEST_WHEN • QUOTES • HAS_APP • RELATIONSHIP_STATUS • HEROES • RELIGION • HUMOR • ROMANCE • ID • SCARED_OF • INTERESTS • SCHOOLS 42
  43. 43. The OpenSocial JavaScript API Working with people: • A Collection represents many opensocial.Person objects. 43
  44. 44. The OpenSocial JavaScript API IdSpec: • idspec is an object that can represent groups of people. var idspec = opensocial.newIdSpec({ quot;userIdquot; : quot;OWNERquot;, quot;groupIdquot; : quot;FRIENDSquot; }); IdSpec can represent only one person: var idspec = opensocial.newIdSpec({ quot;userIdquot; : quot;OWNERquot;, quot;groupIdquot; : quot;SELFquot; }); Or specific data: var idspec = opensocial.newIdSpec({ quot;userIdquot; : quot;1234567890quot;, quot;groupIdquot; : quot;familyquot; }); 44
  45. 45. The OpenSocial JavaScript API Request many people: var idspec = opensocial.newIdSpec({ quot;userIdquot; : quot;OWNERquot;, quot;groupIdquot; : quot;FRIENDSquot; }); req.add(req.newFetchPeopleRequest(idspec, opt_params), quot;keyquot;); • Pass an idspec object to the newFetchPeopleRequest function. • opt_params contains extra request parameters, such as which profile fields to fetch, and how to order or filter the returned people. newFetchPersonRequest responses: var owner_friends = data.get(quot;keyquot;).getData(); owner_friends.each(function (person) { alert(person.getDisplayName()); }); • Data contains a Collection of opensocial.Person objects. Iterate over these by using the each() method. 45
  46. 46. The OpenSocial JavaScript API Working with data: • Persistent data gives apps key, value storage directly on the container. • String only, but conversion to JSON allows for storage of complex objects. • Storage per app per user - scales well with growth. • Ideal for settings, customizations. 46
  47. 47. The OpenSocial JavaScript API Set persistent data: req.add(req.newUpdatePersonAppDataRequest(idspec, key, value)); • idspec can only be “VIEWER”. • key is the name under which this data will be stored. • value is a string representing the data to store. 47
  48. 48. The OpenSocial JavaScript API Fetch persistent data: var idspec = opensocial.newIdSpec({ quot;userIdquot; : quot;OWNERquot;, quot;groupIdquot; : quot;SELFquot; }); req.add(req.newFetchPersonAppDataRequest(idspec, keys), quot;keyquot;); req.add(req.newFetchPersonRequest(quot;OWNERquot;), quot;ownerkeyquot;); • idspec is an object that can represent groups of people, the same as newFetchPeopleRequest. • keys is a list of persistent data keys to retrieve the data for. • The owner is requested because the data returned is indexed by user ID and we want the owner’s data. newFetchPersonAppDataRequest responses: var app_data = data.get(quot;keyquot;).getData(); var value = app_data[owner.getId()][key]; 48
  49. 49. The OpenSocial JavaScript API Fetch persistent data: • Data is returned as an object indexed by ID number, then as an object indexed by key name, even if there is only data returned for one user! { quot;1234567890quot; : { quot;key1quot; : quot;value1quot; } } • One person, multiple keys: { quot;1234567890quot; : { quot;key1quot; : quot;value1quot;, quot;key2quot; : quot;value2quot; } } • Multiple people: { quot;1234567890quot; : { quot;key1quot; : quot;value1quot; }, quot;2345678901quot; : { quot;key1quot; : quot;value2quot; } } 49
  50. 50. The OpenSocial JavaScript API Working with activities: • API to post information about what users are doing with your app. • Many containers have support for images and some HTML. • Channel to grow your application. orkut MySpace hi5 50
  51. 51. The OpenSocial JavaScript API Post an activity: function postActivity(text) { var params = {}; params[opensocial.Activity.Field.TITLE] = text; var activity = opensocial.newActivity(params); opensocial.requestCreateActivity(activity, opensocial.CreateActivityPriority.HIGH, callback); }; • Assign the activity text to the TITLE field. • Call opensocial.newActivity() to create a new Activity instance. • Call opensocial.requestCreateActivity() to post the activity to the container. 51
  52. 52. Building apps across containers 52
  53. 53. Challenges Cross container development is still tricky: • Containers may not follow the standard. • Containers may follow the standard but have different policies. • Follow best practices: http://tinyurl.com/4nuzll 53
  54. 54. Robustness - Be Explicit • Spot the bug in this code! Let's request the owner: function request() { var req = opensocial.newDataRequest(); req.add(req.newFetchPersonRequest( quot;VIEWERquot;), quot;reqquot;); req.send(response); }; function response(data) { var url = data.get(quot;reqquot;).getData().getField( opensocial.Person.Field.PROFILE_URL)); • And access their profile URL: ... } 54
  55. 55. 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: quot;The server will always include ID, NAME, and THUMBNAIL_URL.quot;* *http://rurl.org/qoo 55
  56. 56. 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 ]; 56
  57. 57. Robustness - Be Explicit • Fixing the request: From this... function request() { var req = opensocial.newDataRequest(); req.add(req.newFetchPersonRequest( quot;VIEWERquot;), quot;reqquot;); req.send(response); }; 57
  58. 58. 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( quot;VIEWERquot;, params), quot;reqquot;); req.send(response); }; 58
  59. 59. 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 59
  60. 60. Robustness - Check For Errors 60
  61. 61. 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( quot;14088281537290874435quot;), quot;reqquot;); req.send(response); }; • And get the display name: function response(data) { var name = data.get(quot;reqquot;).getData() .getDisplayName(); ... }; 61
  62. 62. Robustness - Check For Errors • If the passed ID is invalid for any reason, the previous code throws a JavaScript error: data.get(quot;reqquot;).getData() has no properties • Check for problems! DataRequest.send callbacks get DataResponse arguments with hadError methods: function response(data) { if (!data.hadError()) { var name = data.get(quot;reqquot;).getData() .getDisplayName(); ... } }; 62
  63. 63. Robustness - Check For Errors • Inside of these DataResponse objects are nested ResponseItem objects, which also have hadError methods: function response(data) { if (!data.hadError()) { ... } else { if (data.get(quot;reqquot;).hadError()) { ... } } }; • You can check each response individually to see where the point of failure is. 63
  64. 64. Robustness - Check For Errors • Handling errors gracefully: function response(data) { if (!data.hadError()) { ... } else if (data.get(quot;reqquot;).hadError()) { alert(data.get(quot;reqquot;).getErrorMessage()); } else { alert(quot;An unknown error occurredquot;); } }; • getErrorMessage() provides a human-readable error message, but varies by container. • This may not be ideal for display to an end user. 64
  65. 65. Robustness - Check For Errors • getErrorCode() provides an enum indicating the type of error data.get(quot;reqquot;).getErrorCode() • Check for the type of error and fall back where possible. 65
  66. 66. 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 66
  67. 67. Robustness - Check For Errors • Check for error types at runtime: function response(data) { if (!data.hadError()) { ... } else if (data.get(quot;reqquot;).hadError()) { switch (data.get(quot;reqquot;).getErrorCode()) { case opensocial.ResponseItem.Error.BAD_REQUEST: ... break; case opensocial.ResponseItem.Error.INTERNAL_ERROR: ... break; } } else { ... 67
  68. 68. Robustness - Check For Errors • Not all errors need to be fatal! • An appropriate response to UNAUTHORIZED would be to call opensocial.requestPermission() switch (data.get(quot;reqquot;).getErrorCode()) { case opensocial.ResponseItem.Error.UNAUTHORIZED: opensocial.requestPermission( [ quot;VIEWERquot; ], quot;Share a gift with your friendquot;, callback); break; } 68
  69. 69. Robustness - Off Track For A Second • While you can react to an UNAUTHORIZED error, there’s also the opensocial.hasPermission()method, which you can check before making the request: var has_permission = opensocial.hasPermission( opensocial.Permission.VIEWER); • has_permission will be boolean true or false 69
  70. 70. Robustness - Check For Errors • Let’s go back to that requestPermission call: opensocial.requestPermission( [ opensocial.Permission.VIEWER ], “Share a gift with your friend”, callback); • callback will be called when this request completes and get a ResponseItem as a parameter. • What happens if the container doesn’t support requestPermission? 70
  71. 71. Robustness - Check For Errors • Unimplemented methods will get an NOT_IMPLEMENTED error code: function callback(data) { if (!data.hadError()) { ... } else { switch(data.getErrorCode()) { case opensocial.ResponseItem.Error.NOT_IMPLEMENTED: ... break; } } }; 71
  72. 72. Robustness - Check For Errors • A container may not implement any method and still remain spec compliant as long as they return the NOT_IMPLEMENTED error code. • This applies to any method where the callback receives a DataResponse or ResponseItem, including: • requestCreateActivity • requestPermission • requestSendMessage • requestShareApp • all new*Request calls • So be sure to check for such cases! 72
  73. 73. Robustness - Check For Support 73
  74. 74. 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 74
  75. 75. 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? 75
  76. 76. 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_lookingfor has 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? 76
  77. 77. 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_desiretomeet has the following value: • on hi5: JavaScript error • on MySpace: true • on orkut: JavaScript error • Oops! 77
  78. 78. 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_desiretomeet has the following value: • on hi5: false • on MySpace: true • on orkut: false • This approach defeats the purpose of querying! 78
  79. 79. 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; 79
  80. 80. 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 80
  81. 81. Robustness - Check For Support • Don't do this: var env = opensocial.getEnvironment(); var supports_presence = env.supportsField( opensocial.Environment.ObjectType.PERSON, hi5.PersonField.PRESENCE); var supports_desiretomeet = env.supportsField( opensocial.Environment.ObjectType.PERSON, MyOpenSpace.Person.Field.DESIRE_TO_MEET); var supports_lookingfor = env.supportsField( opensocial.Environment.ObjectType.PERSON, opensocial.Person.Field.LOOKING_FOR); 81
  82. 82. 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, quot;presencequot;); var supports_desiretomeet = env.supportsField( opensocial.Environment.ObjectType.PERSON, quot;DESIRE_TO_MEETquot;); var supports_lookingfor = env.supportsField( opensocial.Environment.ObjectType.PERSON, quot;lookingForquot;); 82
  83. 83. Robustness - Check For Support Wait a sec, isn’t this a worst practice? 83
  84. 84. 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.” 84
  85. 85. Robustness - Check For Support • Thankfully, the specification addresses this issue: “For example, if the field orkut.PersonField.SPECIAL_FIELD is defined as 'orkut.specialPersonField', then opensocial.getEnvironment().supportsField( quot;personquot;, quot;orkut.specialPersonFieldquot;) and opensocial.getEnvironment().supportsField( opensocial.Environment.ObjectType.PERSON, orkut.PersonField.SPECIAL_FIELD) should both return true.”* *http://rurl.org/qr4 85
  86. 86. Robustness - Check For Support • We now have runtime access to capabilities across all containers: hi5 MySpace orkut supports_presence TRUE FALSE FALSE supports_desiretomeet FALSE TRUE FALSE supports_lookingfor FALSE FALSE TRUE • Drawback: Now we have to be sensitive to the underlying string value for Profile field enums 86
  87. 87. Robustness - Check For Support • Now, instead of: • Use: if (MyOpenSpace) { if (supports_presence) { ... ... } else if (hi5) { } ... if (supports_desiretomeet) { } else { ... ... } } if (supports_lookingfor) { ... } 87
  88. 88. Resources / Questions? 88
  89. 89. Resources • OpenSocial Tutorial: http://rurl.org/ss3 • OpenSocial Spec, Foundation, Reference: http://opensocial.org • Caja: http://code.google.com/p/google-caja/ • Shindig: http://incubator.apache.org/shindig/ • OpenSocial Across Containers video: http://tinyurl.com/4nuzll • OpenSocial Templates: http://ostemplates-demo.appspot.com/ • OpenSocial Dev App: http://osda.appspot.com • Partuza: http://partuza.nl • OpenSocial Specification Proposals: http://groups.google.com/group/opensocial-and-gadgets-spec/topics 89
  90. 90. Hacking! Beginner (http://is.gd/7W05): • Write a gadget to display quot;Hello Worldquot; in your favorite container. • Display a list of your friends. • Display the OWNER's favorite movies. • Post an activity update. • Write an app that uses AppData to store preferences (http://is.gd/7W0g) Intermediate: • Make an app that works on two containers using the same XML. • Use makeRequest to list the OWNER's favorite movies and information from a web API such as amazon.com or imdb.com • Write a gift giving app using AppData: (http://is.gd/7W0v) Advanced: • Write a server-side app that uses the Java (http://is.gd/7W0E) or PHP (http://is.gd/7W0K) client libraries. 90
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×