ecmanaut

The author

2005-12-05, 20:07

Designing useful JSON feeds

Technical background: JSON, short for the javascript object notation is, much like XML, a way of encoding data, though in a less spacious fashion, and one which is also compatible with javascript syntax. A chunk of very terse XML to describe this blog might look like this:
<blog>
<u>http://ecmanaut.blogspot.com/</u>
<n>Johan Sundström's technical blog</n>
<d>ecmanaut</d>
</blog>

The top element, as an aside, is required in XML, even if we don't assign any special data to it. In JSON, the above entry would look like this instead:
{"u":"http://ecmanaut.blogspot.com/","n":"Johan Sundström's technical blog","d":"ecmanaut"}

This makes for a smashing combination of light-weight data transport and easy data access for javascript applications. With very little extra weight added to a chunk of JSON, it also enables javascript applications to query cooperative remote servers for data, read and act on the results, which is something the javascript security model explicitly forbids javascript to do with XML, or HTML and plain text. (As a way of protecting you from cross site scripting security holes, which is a good thing to avoid.)

Anyway, with JSON, and a bit of additional javascript to wrap it, we can include data from some other domain given that wants to share data with us, using a script tag we point there, the data will be loaded and available to other scripts further down on the page in a common variable. This is a great thing, whose use is slowly spreading, with pioneering sites such as the cooperative bookmarking and tagging service Del.icio.us, that offers not only RSS feeds of the bookmarks people make, but also JSON feeds.

This article will show what Del.icio.us does, why they do, and suggest best practices for making this kind of JSON feeds even more useful to applications developers. This is what Del.icio.us adds to the bit of JSON above:
if(typeof(Delicious) == 'undefined')
  Delicious = {};
Delicious.posts = [
{"u":"http://ecmanaut.blogspot.com/","n":"Johan Sundström's technical blog","d":"ecmanaut"}]

This does two things. First, it peeks to see if there is already a Delicious object defined. If it isn't, it makes a new one, a plain empty container. This is a good way of making sure that other data sources in your API can be included later on in the page, coexisting peacefully without overwriting one another, or adding variable clutter in the global scope. (It is also good for branding! ;-) Then, it assigns our bit of JSON into the first element of an array -- or, in case we asked for lots of entities, fills up an entire arrayful of them.

Now, a later script on the page can do whatever it wants with the data in Delicious.posts, and all is fine and dandy. This is how the category menu on the right of this blog is built, by the way, asking Del.icio.us for posts on my blog carrying the appropriate tag. (In case this sounded very interesting, read more in this article.)

This is all you need for static content pages, being loaded with the page, parsed and executed once only. AJAX applications are typically more long lived, and often do what they do without the luxury of reloading themselves as soon as they want more data to crunch on. Adding support for this isn't hard either: this is what we add at the end of our JSON feed:
if(Delicious.callbacks && Delicious.callbacks.posts)
Delicious.callbacks.posts( Delicious.posts );

What happens here? Well, first we peek to see if there is a Delicious.callbacks object defined. If there is, we peek inside it, to see whether there is a callback Delicious.callbacks.posts installed for the page that sends the Delicious.posts data. If there was, we call it, passing the data, and let the callback do whatever its application requires of it.

A very rudimentary example script using the API could now look like this:
<script type="text/javascript">
Delicious = { callbacks:{ posts:got_posts, tags:got_tags }};
function got_posts( posts )
{
alert( posts.length + ' posts matched.' );
}

function got_tags( tagnames, usernames )
{
alert( tagnames.length + ' tags shared by ' +
usernames.length + ' users.' );
}</script>
<script type="text/javascript" src="http://api.url/">
</script>

The tags member of the callbacks object is for another (fictious) API, which in this example is called with two arrays of data, one carrying a number of tag names, the other an array of user names who use all of these tags.

With a callback approach like this, an AJAX application can create new <script> tags to its page to perform successive requests to a data source and get alerted of the new data when it arrives. As neither HTML nor javascript provide any means of annotation for when a <script> tag has completed loading, we would otherwise have to do lots of housekeeping and polling to find out when the new content arrives, or to perform advanced feats of magic most javascript programmers are not familiar or comfortable with. Callbacks solve that.

The approach outlined above does not solve another problem, though: handling multiple simultaneous requests. To do that, we also need to be sure each request gets handled by its own callback. This is best solved as a separate mode of invoking your API, by providing an additional URL parameter stating the name of the callback to run, or, more precisely, what javascript expression that should be invoked to call the right callback with your data. With this direct approach, we are best off not assigning any variable at all, but rather just pass the callback the data we feed it, right away.

Assuming our query parameter be named cb, we get invoked like this:
<script type="text/javascript" src="http://api.url/?cb=callbacks[17]">
</script>

and we return the code (as this is a call for our fictious tags call):
if(typeof callbacks[17] == 'function')
  callbacks[17]( ["Web2.0","Del.icio.us"],
                 ["John","Eric","Bruce"] );

-- copying the parameter verbatim.

And the web is suddenly a slightly better place than it was, thanks to your application.

7 Comment:

  • I definately understand much better now why you encouraged the callback functions for the JSON in Commentosphere. This passing the callback in the GET string intrigues me as well... but I'm not sure I entirely understand it. We pass the name of the callback function in the get string and then the script that comes with the JSON somehow invokes that?

    By Blogger Singpolyma, on Tue Dec 06, 07:53:00 AM CET  

  • Hi again Johan,

    You mentioned in your comment in browservulsel's custom comment form post that you've found a way to make the CAPTCHA work for IE6.

    I've commented a question, at
    browservulsel's custom comment form
    .

    If you be so kind as to reply. I would really appreciate it.

    Thanks again, Johan.

    By Anonymous dreamflow, on Tue Dec 06, 01:27:00 PM CET  

  • Johan,

    Not sure where to place this comment, certainly doesn't really belong in this post.

    Anyway, blogger was down for some hours yesterday. This morning it is back up, however your greasemonkey categorizer/pinger no longer works (at least not for me). It worked splendidly as usual just before the blogger outage. Now it appears to execute fine including posting at del.icio.us but when I view the blog or post, the category tags are not there.

    I uninstalled and reinstalled it, but to no avail.

    Thought you'd want to know that. Don't know if anyone else is having problems. I should mention that I installed a couple of new FFox extensions last night so I don't know if that's having an effect.

    By Blogger Jim, on Tue Dec 06, 03:13:00 PM CET  

  • (I would have picked the page introducing the script, but never mind that.) Ouch. If that is the case, and I would presume it is (without having had a look at it myself yet), I'll most likely not have a solution done until some time Thursday, since I am on a trip at the moment.

    These things will always happen from time to time with Greasemonkey scripts, unfortunately. Should anyone fix it before I do, please leave a note and link to the result, so others can be relieved of the pain as quickly as possible.

    By Blogger Johan Sundström, on Wed Dec 07, 07:51:00 AM CET  

  • Regarding the callback: spot on. The JSON code we include in the page gets parsed and executed where it got inserted, just like any other code in the page, so all we need to do is tell the JSON generator the name of the function, and it can invoke it, using that name. It's just like any other code of yours; nothing particularly magic about it at all. No eval()s needed, or anything; we are injecting external code into our live page, and it gets to share our name space with all its contents.

    By Blogger Johan Sundström, on Wed Dec 07, 08:13:00 AM CET  

  • Johan, yes the originating page would have been the obvious choice but I wasn't sure if you were still checking comments on that one. sorry about that.

    And it's working okay now. I eliminated one of the extensions (it converted plain text url's to actual links,it was the last extension I downloaded during the outtage).

    Feel free to delete these comments if they're mucking up the conversation on this post.

    By Blogger Jim, on Fri Dec 09, 02:49:00 AM CET  

  • Whew, good to hear. :-)

    I wasn't sure if you were still checking comments on that one. sorry about that.

    Fortunately the blog owner gets mail annotation of posts, so we can track what happens everywhere. In a while, Stephen's current hack projects will render us all RSS feeds for comments both for specific posts and whole blogs, which will be even nicer still. All in due time, though. :-)

    Feel free to delete these comments if they're mucking up the conversation on this post.

    Naah, can't be that picky; it's valuable feedback, and people should be encouraged to get back to me with such concerns (I posted a tutorial that was buggy in IE and didn't realize just how bugged it was for weeks) so I can address them.

    By Blogger Johan Sundström, on Fri Dec 09, 02:57:00 AM CET  

Post a Comment

http://ecmanaut.blogspot.com/2005/12/designing-useful-json-feeds.html

09:30

Styling your blog post tags list with CSS

Freshblog just posted an excellent step by step tutorial on how to categorize your Blogger blog posts using my Greasemonkey post tagger tool. This post adds a bit on how you can use CSS to add some stylish looks to the tags you end up with listed at the bottom of your blog posts.

Assuming you use this tool, or one of its ancestors and relatives, or doing it manually yourself, posts in your blog with one or more tags will get this bit of HTML appended to the post (provided it has been tagged with "Blogger" and "CSS", the Del.icio.us account used is Ohayou, and the anchor tag used is "ecmanaut" -- yours will differ):

<div class="tags">Categories:<ul><li><a href="http://del.icio.us/ohayou/ecmanaut+Blogger" rel="tag">Blogger</a></li> <li><a href="http://del.icio.us/ohayou/ecmanaut+CSS" rel="tag">CSS</a></li></ul></div>

A bit terse, yes, but there is good reasoning behind it. First, people won't read the HTML of your post, so the lack of newlines and additional whitespace will not bother anyone. Second, if it had had any newlines between tags, that would introduce extra <br> tags on blogs that use the Blogger convenience setting to substitute newlines for HTML line break tags, and that might complicate styling this list the way you want it to look. Without any special CSS treatment of yours, this might look a bit like this in your blog (if you use the same basic page template I do, anyway):

Categories:
The first thing you might want to change about the above is the way it adds a line break between every tag instead of listing them all on one line. Find the place in your page template that reads <style type="text/css"> and add this bit of CSS right afterward:

div.tags ul { display:inline; padding:5px; }
div.tags li { display:inline; }

The first line makes the first tag line up with the "Categories:" text, the second makes consecutive tags line up right along with the previos tag. The explicit padding in the example might not be needed, depending on what other CSS is at play, but if you experience something looking like a tab between the label and first tag, you want it. Similarly, if there is way too much space between tags, you might need to adjust the li line in the same fashion.

But we might want to add some nice little icon label next to each tag, that differentiates them from all the other bullet lists on your blog. These are Del.icio.us tags, after all; how about showing the Del.icio.us tag icon instead? That could look like this (feel free to copy their image and put it somewhere else, if you don't want to feed them any data about your visitors, the amount of traffic your blog gets, and so on):

div.tags ul { display:inline; }
div.tags li { padding-left:14px; margin-left:8px; background: url('http://del.icio.us/static/img/delicious.small.gif') no-repeat 0 3px; display:inline; }

The padding and margin adds a few pixels to the left of each tag for the icon, and the background specification fills the space with the icon. The 3px figure at the end might need adjusting; it's how far down (in pixels) the icon should be in relation to the top of the list item and this will vary slightly with the size of the font you use. Three pixels works for my setup; yours might require more or less; try it out and see if you are happy with the results, and change accordingly otherwise.

You can of course add lots of other things too using CSS, and this is not trying to be a tutorial on all the possibilities on offer, but it's a head start, anyway. Good luck with your own styling!

Q: I have a blog based on the TicTac template, just like yours; how did you get your tags formatted like the text in the TicTac post footer?


A: I did it like this, altering the .post-footer sections to also apply to my div.tags tag list. If you don't want your tags capitalized, do not copy the text-transform:capitalize; bit.

.post-footer,div.tags {
  margin: 0;
  padding: 0 0 0 14px;
  font-size: 88%;
  color: #999;
  background:url(http://www.blogblog.com/tictac_blue/tictac_grey.gif) no-repeat 0 8px;
}

.post-body div.tags { margin:1em 0 0; }
div.tags ul { display:inline; margin-left:0; }
div.tags li { display:inline; margin-left:8px; text-transform:capitalize; }
.tags li {
  background:url('http://del.icio.us/static/img/delicious.small.gif') no-repeat 0 3px;
}

CSS tricks for custom bullets describes in greater detail and clarity what these things are all about, and how you can be creative with unordered lists using CSS. Well worth a read for all of you that want to add your own touch of creativity to your template.
Categories:

35 Comment:

Post a Comment

http://ecmanaut.blogspot.com/2005/12/styling-your-blog-post-tags-list-with.html