MySpace Open Platform

A Place For Developers

Welcome Developers!

in

Welcome!

in

Example app: RSS Reader

In this post I hope to get you off the ground in terms of how to request data from other sites using the OpenSocial API. Remember that in OpenSocial your application is hosted in the browser and served off the container's domain (in this case, MySpace). XHRs (XML Http Requests) cannot be issued across domains (for example, Javascript hosted off of http://www.myspace.com cannot access data from http://www.google.com). Because of that restriction, you can't make a straight call to another domain. The OpenSocial API provides a simple mechanism called "makeRequest" that allows you to request data from any domain you want.

MakeRequest gets around the XHR cross-domain restriction by utilizing a custom http proxy hosted by MySpace. This proxy relays incoming requests to other sites and pipes the results back to the browser. It also optionally signs the requests using the OAuth methodology (the specifics will be covered in another article). It is important to note that this is not a standard open proxy--it does its best to verify that the request came from a valid OpenSocial application hosted on MySpace.

MakeRequest method signature:

opensocial.makeRequest(url,callback,opt_param)

url

The url you wish to be called.

callback(data)

The function you wish to be called with the results. The signature of the function should have at least one parameter (which will contain a reference to the data returned by the call).

 opt_param

A bucket for a set of standard OpenSocial parameters that tell the proxy how to behave. There is quite a bit of functionality accessible through the manipulation of this object. To give you a taste of what you can do, below is some example code that exercises opt_param to its fullest.

code snippet 1 : Drill down into makeRequest parameters
function getRss(){ var url = "http://www.codeproject.com/webservices/articlerss.aspx?cat=1"; var params = {}; //Lets makeRequest know that the result will be an XML document. params[opensocial.ContentRequestParameters.CONTENT_TYPE] = opensocial.ContentRequestParameters.ContentType.XML; //Sets the request method to POST (default is GET). params[opensocial.ContentRequestParameters.METHOD] = opensocial.ContentRequestParameters.MethodType.POST; //Adds two custom headers to the request. These headers will be passed on to the target. params[opensocial.ContentRequestParameters.HEADERS] = {"x-myheader":"myheadervalue", "x-myotherheader":"myotherheadervalue"}; //Tells the proxy to sign the request using OAuth. params[opensocial.ContentRequestParameters.AUTHORIZATION] = opensocial.ContentRequestParameters.AuthorizationType.SIGNED; opensocial.makeRequest(url, makeRequest_callback, params); }

So goes the request. opt_param takes a bucket of constants that you can use to tweak the request:

opensocial.ContentRequestParameters.CONTENT_TYPE 
    (takes a value from: opensocial.ContentRequestParameters.ContentType)
opensocial.ContentRequestParameters.METHOD 
    (takes a value from: opensocial.ContentRequestParameters.MethodType)
opensocial.ContentRequestParameters.HEADERS 
    (takes a key-value bucket)
opensocial.ContentRequestParameters.AUTHORIZATION 
    (takes a value from: opensocial.ContentRequestParameters.AuthorizationType)

This is not the official documentation for makeRequest, so I won't go into many details--instead I'll go on to create the app:). The code that parses the response is quite simple:

code snippet 2 : Response handling code
function makeRequest_callback(data,error){ if (data == null) { $("rssDisplay").innerHTML = "no data returned--check your RSS url!"; return; } var channelList = data.getElementsByTagName("channel"); var channel = new RSSChannel(channelList[0]); $("header").innerHTML = getTag("h1", channel.Title); $("rssDisplay").innerHTML = channel.render(); }

The example application in this post is an RSS reader that uses a custom bit of code that translates XML into JavaScript objects. Parts of that code will be a lovely exercise in redundancy. Why? Because OpenSocial exposes an RSS implementation that is more robust than the one in this article. This article is more about how to call a third party site and parse the results (be they XML, JSON, or some other format). A lot of sites happen to expose XML in RSS, so I'm using such exposure as an example. In other words, this article continues the long and storied tradition of useless demo-code--sit back and enjoy!

MakeRequest: Simple RSS Reader Application

MakeRequest is for pasing data to and receiving data from your site (or, in the case of a mashup, a third party's site). Its method signature is:

First, let's set up some chrome and an initialization function:

code snippet 3 : Simple chrome for application
<style> body { background-color: whitesmoke; } h1 { font-size: medium; } #rssDisplay { border: 1px solid; height: 240px; overflow: auto; padding: 3px; background-color: white; } #rssDisplay p { font-size: small; } </style> <div id="container"> <div id="header"> </div> <div id="rssDisplay"> </div> <script> function getRss(){ //this will get the feed } getRss(); //initialize the application </script> </div>

Above we have the trappings of an application--with no functionality. We'll now fill in the getRss() call with Javascript that calls the RSS feed (which happens to be the latest articles from "The Code Project").

code snippet 4 : Completed application
<style> body { background-color: whitesmoke; } h1 { font-size: medium; } #rssDisplay { border: 1px solid; height: 240px; overflow: auto; padding: 3px; background-color: white; } #rssDisplay p { font-size: small; } </style> <div id="container"> <div id="header"> </div> <div id="rssDisplay"> </div> <script> /* * makeRequest implementation */ function getRss(){ var url = "http://www.codeproject.com/webservices/articlerss.aspx?cat=1"; var params = {}; //This parameter lets makeRequest know that the result will be an XML document. params[opensocial.ContentRequestParameters.CONTENT_TYPE] = opensocial.ContentRequestParameters.ContentType.XML; opensocial.makeRequest(url, makeRequest_callback, params); } function makeRequest_callback(data, url, error){ if (data == null) { $("rssDisplay").innerHTML = "no data returned--check your RSS url!"; return; } var channelList = data.getElementsByTagName("channel"); var channel = new RSSChannel(channelList[0]); $("header").innerHTML = getTag("h1", channel.Title); $("rssDisplay").innerHTML = channel.render(); } /* * Utility functions */ //Cross browser grabber for text in an xml element function getNodeText(node){ if (node.text != null) return node.text; else return node.textContent; } //Simple, non-performant tag renderer function getTag(tag, txt){ return "<" + tag + ">" + txt + "</" + tag + ">"; } //Adds a tag to a string function appendTag(str, tag, txt){ str += getTag(tag, txt); } /* * RSS Feed Wrapper Objects */ function RSSChannel(node){ for (var i = 0; i < node.childNodes.length; i++) { var childNode = node.childNodes.item(i); switch (childNode.nodeName) { case "title": this.Title = getNodeText(childNode); break; case "link": this.Link = getNodeText(childNode); break; case "description": this.Description = getNodeText(childNode); break; } } var items = node.getElementsByTagName("item"); this.RSSItems = []; for (var i = 0; i < items.length; i++) { var item = items.item(i); var rssItem = new RSSItem(item); this.RSSItems.push(rssItem); } } RSSChannel.prototype.render = function(){ var output = ""; // output += "<h1>" + this.Title + "</h1>"; for (var rssItemId in this.RSSItems) { var rssItem = this.RSSItems[rssItemId]; if (rssItem.IsValid != null && rssItem.IsValid()) output += rssItem.render(); } return output; }; function RSSItem(node){ this.Title = ""; this.Description = ""; this.Link = ""; this.Author = ""; if (node.childNodes == null) return; for (var i = 0; i < node.childNodes.length; i++) { var childNode = node.childNodes.item(i); switch (childNode.nodeName) { case "description": this.Description = getNodeText(childNode); break; case "title": this.Title = getNodeText(childNode); break; case "link": this.Link = getNodeText(childNode); break; case "author": this.Author = getNodeText(childNode); break; } } } RSSItem.prototype.render = function(){ var output = "<p>"; output += "<a target=\"_top\" href=\"" + this.Link + "\" title=\"" + this.Description + "\">"; output += this.Title; output += "</a>"; output += "<br />"; output += "<i>by " + this.Author + "</i>"; output += "</p>"; return output; }; RSSItem.prototype.IsValid = function(){ if (this.Title != null && this.Title != "") return true; }; getRss(); </script> </div>

And there you have it. A simple RSS reader. Don't expect the code to parse all types of RSS feeds :).

Comments

 

Marco said:

Good stuff. No smoke and mirrors in your code samples. Only some white smoke on the background :)

February 5, 2008 11:21 PM
 

Nick said:

Which RSS version does it support ?

February 6, 2008 11:16 AM
 

Chris said:

It supports a new kind of RSS called "Buggy RSS" :).  I wouldn't recommend the example code against different RSS feeds.

February 8, 2008 6:08 PM
 

JackTard said:

I attempted to "Edit Souce" with this code, but I'm missing a key understanding. Where did I terribly wrong. Please explain. I started this thread to explain what I do and don't understand. You're help is appreciated.

developer.myspace.com/.../805.aspx

February 9, 2008 4:23 AM
 

Shane said:

I copied and pasted your source into my application, tested, and swoosh, it runs great!  I then copied the rss xml from your server and pasted that into an xml file on my server. www.bodyigniter.com/.../experimentalData.xml.  Next, I modified var url = "www.bodyigniter.com/.../experimentalData.xml";  Firebug reports that "data.getElementsByTagName is not a function"  Being a bit ignorant, I thought perhaps I should pass the xml file through PHP to fulfill some requirement of makeRequest() (located at www.bodyigniter.com/.../experimentalData.php).  I updated the url to point to the new php wrapper and that got rid of the "data.getElementsByTagName is not a function" error.  However, the data returned is null.  At the moment both the XML file and the PHP are accessible on my server.  Visiting those addresses return exactly what your xml contains.  What gives?  It seems that makeRequest() and it's magic proxy is clearing the xml.

February 9, 2008 4:42 PM
 

Chris said:

Hmm!  The example RSS in the code isn't from a site of mine, it's from The Code Project, a popular programming site. So there's no special sauce in how it's grabbing it. You should be able to store it as a simple xml file (no php required). I'll give your feed a try later today and let you know what I see.

February 11, 2008 12:02 PM
 

AlexNull said:

Thanks for sharing this code to start with Open-social Api. Hope getting soon authorithed to start developing apps for myspace!!

February 12, 2008 1:16 AM
 

chaomeng said:

Thank you for your sharing code, which help me start my first app for myspace.

Another question, Learned from the forum that there is a conclusion that OpenSocial is a widget platform, not an application platform, is that true? If not, how can I develop a relatively richer feature application, such as a quiz, the simplist application in facebook. Thank you in advance.

February 14, 2008 7:22 PM
 

DotNetAllDay said:

This example is pretty much a pure play javascript app. Are there any examples for a Flash application? Thanks!

March 13, 2008 4:11 PM
 

Zoasterboy said:

Awesome!

This will come in handy right away.

March 17, 2008 5:26 PM
 

Fair Trade Wales 2008 said:

Any apps made that display rss feeds ? That are Live ?

March 20, 2008 6:21 AM
 

ant**** said:

You'll need remove the prototype methods to get this work, following link

June 11, 2008 3:00 AM
 

ant**** said:

June 11, 2008 5:37 AM
 

E-TARD said:

hmm thanks

July 13, 2008 11:23 AM
 

Robert said:

Does anyone have a fully working example of this?

Does the code just go in to the "Profiile surface" that you see when you create an app?

Thanks.

August 6, 2008 5:56 PM
 

Ed said:

This code is problematic.  I used ant****'s code for correction and that works fine with an RSS feed from Yahoo or Wired but when I author my own is get a Javascript error saying that the "object does not support this property or method"

It works with Yahoo or Wired but when I author my own RSS feed which is valid it does not work.  Am I missing something?

Below is the URL for the RSS feed I have created:  

69.33.31.110/.../shoeFeed.aspx

September 2, 2008 2:09 PM
 

IMIStudent said:

Code is still not working...???

anyone solved the problem?

thanks

June 25, 2009 5:38 AM