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 :).

Published Sunday, February 24, 2008 1:47 AM by Chris
Filed under:

Comments

# re: Example App: RSS Reader

Monday, March 31, 2008 10:35 PM by Zoasterboy

Awesome! Just what I've been looking for. Thanks!

Powered by Community Server (Commercial Edition), by Telligent Systems