JSON Feeds For Fun and Profit Part 2 – Callbacks with Twitter

In my first exploration of the JSON data interchange format, I used it in its most basic way possible. I attached a script (from delicious) to a page and simply used the built-in object created by their implementation to generate an unordered list of my recent del.icio.us posts. While it showed how easy it is to use the O, a handy, structured, Javascript Object, provided by JSON, it didn’t really illustrate how to manipulate the page with new data after page load. That is, after all, a very now thing to do, so it’s kind of important. This article will examine how to dynamically load a JSON feed and how to get data out of Twitter and into a usable form using a callback.

While one can load JSON using XMLHttpRequests, the real benefit of JSON is to be able to load data from a third party without worrying about the browser security model and without having to rely on a local pass through file. So, we’re going to load the data without XHR in this example. Instead we’re going to load it using dynamic script tags.

Here’s the function I’m using in my example:

function twitter_me() {
   var twitter_JSON = document.createElement("script");
   twitter_JSON.type="text/javascript"
   twitter_JSON.src="https://twitter.com/statuses/user_timeline/rob_react.json?callback=twitter_callback&count=10"
   document.getElementsByTagName("head")[0].appendChild(twitter_JSON);
}

First I create a new script element in the document, then I set the type and source. The source is the interesting part. As you can see, after the URL for the JSON document representing my Twitter updates, I append a query string. The first argument for that query string (callback=twitter_callback) is where the magic happens. There I’m defining the function that will be called when the script is attached to the document. To see what happens compare the first few characters of the JSON script called with and without the callback.

Here it is, as referenced in the above code

twitter_callback([{"source":"web","text":"426 queries in 107.66 milliseconds. drupal is teh awesome",

and called without the callback (but with the count, so the data structure returned is the same)

[{"source":"web","text":"426 queries in 107.66 milliseconds. drupal is teh awesome",

Notice the function referenced in the first example. Right there, as soon as the JSON document is loaded, JavaScript executing the callback function with the JSON object as an argument. I’m a JavaScript geek and all, so I’m biased… but that’s just plain cool.

So what happens next, you ask? Well, since I defined a function called twitter_callback, that function is run and I’m able to do all sorts of cool things with the provided object. Here’s the function in all its glory:

function twitter_callback(twit) {

//this is the div I'm writing the content to
var t_div = document.getElementById("twitter");

//these are some other variables, mostly
//placeholders so that the code is a little clearer
var who,what,when,icon, bgcolor

//start the ul
t_div.innerHTML = "<ul>"

//loop through the twit object
for (i=0;i<twit.length;i++) {

//Look at me use the JavaScript modulus operator to do even/odd rows.
if(i % 2) {
bgcolor="#efefef"
} else {
bgcolor="#ddd"
}

//Right here, I've broken out the separate bits of the string into placeholder variables
//so you can more easily see the dot notation and array indices in place
//once you figure out the structure it's dead easy to reference data in an Object
icon=twit[i].user.profile_image_url;
who=twit[i].user.name;
what=twit[i].text;
when=twit[i].created_at.substr(0,19);

//and here I mash it all up into a fancy li
t_div.innerHTML +="<li style='background:"+bgcolor+" url("+icon+") no-repeat'><strong>"+who+"</strong>: "+what+" ("+when+" GMT) </li>"
}
//and close the UL
t_div.innerHTML += "</ul>"
}

Here it is in action (be patient, Twitter can be slow):

Call me crazy, but that’s something like 75% away from being a widget and there are no cross domain concerns to deal with so it could easily be spread far and wide. There’s a lot to like right there 🙂

That’s it for this time. Feel free to ping me with questions or comments.

Next up, as I mentioned, one can load JSON via XMLHttpRequest, so I’ll be building an example that does just that. There’s a wrinkle tossed in with that technique that will make things, if not tougher, a little less cool (eval(), I’m looking in your direction.) More on that when I put it all together.

18 thoughts on “JSON Feeds For Fun and Profit Part 2 – Callbacks with Twitter

  1. This is very interesting, but I don’t understand two things:

    1. What is creating the twit object?
    2. What is calling the twitter_callback function and passing that object?

  2. Sorry, I still don’t really get it.

    If I request http://twitter.com/statuses/user_timeline/rob_react.json without the query string, I get a JSON string containing an array of 20 user objects.

    If I request http://twitter.com/statuses/user_timeline/rob_react.json?callback=twitter_callback&count=10, I get a JavaScript call to twitter_callback, passing as an argument a JSON array of 10 user objects. I see that the count parameter controls the array size.

    So the first thing I don’t understand is how passing that query string to rob_react.json changes the response. I have thought of JSON as a data format, not a programming language. But I think what’s happening here is that rob_react.json is a program that knows how to read the query string and change behavior accordingly. Is that correct? Is the parameter name “callback” in the query string some kind of special name?

    Let’s see if I can accurately describe this process:

    1. Using script A, define a new script element. Make its source attribute value be the URL of script B. Add to that URL a query string naming a function defined in script A. Add one or more other parameters to the query string to control what script B returns. (But how does script B use the parameters?)

    2. Append this new script element to the head element of the current document.

    3. When the document is loaded, script A executes. It adds the reference to script B to the document head.

    4. Script B is loaded and returns a function call with an object passed as a parameter to the function.

    5. That function call executes and calls the callback function in script A.

    6. The callback function in script A traverses the object passed in from script B and modifies the current document.

  3. Never mind the questions above. Now I understand that for this to work, the JSON feed must come from a Web service that knows to parse the query string in the request, look specifically for the “callback” parameter and render the response accordingly.

  4. That’s it exactly. It’s still the same data format, just this time with an-easier-to-ingest wrapper in the form of a callback.

    This is definitely my preferred method of dealing with JSON. No XMLHttpRequests, no eval(), just a nice function call.

  5. I’m not sure about what twitter promises when calling the public timeline, but to make it work you’ll have to grab the script via XMLHttpRequest (and a local proxy to get around domain security issues) and eval() the response into a useful javascript variable.

    It’s odd that the Object literal in the response is wrapped in an Array literal.

  6. Thanks for the swift reply 🙂

    I was experimenting with retrieving stuff whilst at work using a page on my local machine so I don’t think the local proxy is a goer. Shame as the cross domain issue for Ajax is a real pain and JSON seems to be the answer.

    Once again, many thanks.

  7. I was able to get this working as you described for a user. How do I make this work for a Hashtag. I have replaced your src with the following and neither work:

    twitter_JSON.src=”http://search.twitter.com/search.json?q=&tag=haiku&callback=twitter_callback&count=10″

    twitter_JSON.src=”http://search.twitter.com/search.json?q=%23haiku&callback=twitter_callback&count=10″

  8. Hi,

    That’s a really interesting question. Let me take a look today and if it’s simple, I’ll post the response here. If not, I’ll write up an answer for a new post (I told you it was interesting.)

  9. Hi,

    Looking at the response from twitter, the structure of search results is different than the results for a status query

    Compare search

    twitter_callback(
    {"results":
    [{"text":"@MAndrewSprong I have lost three dogs\/ to cars. I hope that heaven\/ is vehicle free.

    to status

    twitter_callback([{"created_at":"Thu Oct 30 13:43:23 +0000 2008","text":"@dalecruse talking to yourself now?",

    I’ll do a write up on how to handle search results later on today. I haven’t written up any code articles in a few weeks.

  10. Hey, this was really helpful. I had already written a proxy handler in Sinatra just so I could work around the cross-domain restrictions before I found this.

    Much simpler solution. Thanks!!

  11. i’ll take a look. I just moved a bunch of posts over from my other domain so something might have been lost in the shuffle. That, or the format changed in 3 years and you’re the first person to point it out… In which case, i’ll revisit and make it work once again.

  12. does this callback work for any of the json file? Or is it should be public, or need to do something?

Leave a Reply

Your email address will not be published. Required fields are marked *