<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Joseph Smarr &#187; Web development</title>
	<atom:link href="http://josephsmarr.com/category/web-development/feed/" rel="self" type="application/rss+xml" />
	<link>http://josephsmarr.com</link>
	<description>Thoughts on web development, tech, and life.</description>
	<lastBuildDate>Sat, 21 Jan 2012 18:06:41 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com"/><atom:link rel="hub" href="http://superfeedr.com/hubbub"/>		<item>
		<title>Winning Market Share in the Sharing Market</title>
		<link>http://josephsmarr.com/2012/01/05/winning-market-share-in-the-sharing-market/</link>
		<comments>http://josephsmarr.com/2012/01/05/winning-market-share-in-the-sharing-market/#comments</comments>
		<pubDate>Thu, 05 Jan 2012 18:17:18 +0000</pubDate>
		<dc:creator>joseph</dc:creator>
				<category><![CDATA[Open Social Web]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://josephsmarr.com/?p=106</guid>
		<description><![CDATA[[Usual disclaimer: I currently work for Google on Google+ (which I think is awesome), but as always the thoughts on this blog are purely my personal opinion as a lifelong technology lover and builder.] At the core of innovation in social networking is the competition to be a user’s tool of choice when they have [...]]]></description>
			<content:encoded><![CDATA[<p><em>[Usual disclaimer: I currently work for Google on Google+ (which I think is awesome), but as always the thoughts on this blog are purely my personal opinion as a lifelong technology lover and builder.]</em></p>
<p>At the core of innovation in social networking is the <strong>competition to be a user’s tool of choice when they have something to share</strong>. Most people go to social networks because their friends are sharing there, and there is an inherit scarcity to compete for because most people aren’t willing to share something more than once (some may syndicate their content elsewhere, if permitted, but the original content is usually shared on a single service). Thus every time people are moved to share, they must choose which tool to use (if any)&#8211;a social network, via email/sms, etc.</p>
<p>Conventional wisdom holds that the main factor determining where a user will share is <em>audience size</em> (i.e. where they have the most friends/followers, which for most people today means Facebook or Twitter), but the successful rise of services like Foursquare, Instagram, Path, Tumblr, and Google+ shows that there’s more to the story. Despite the continued cries of “it’s game-over already for social networking” or “these services are all the same”, I don’t think that’s the case at all, and apparently I’m not alone.</p>
<p>These newer services are all getting people to share on them, even though in most cases those users are sharing to a smaller audience than they could reach on Facebook or Twitter. What’s going on here? It seems to me that these services have all realized that the<strong> competition for sharing is about more than audience size</strong>, and in particular includes the following additional two axes:</p>
<ul>
<li>Ease of sharing to a more specific/targeted audience</li>
<li>Ease of sharing more tailored/beautiful content</li>
</ul>
<p><strong>Sharing to a more specific/targeted audience</strong> sounds like the opposite of “sharing where all of my friends/followers already are”, but not everything we say is meant to be heard by everyone. In fact, when I ask people why they don’t share more online, two of the most frequent responses I get have to do with having <em>too much</em> audience: <strong>privacy</strong> and <strong>relevance</strong>. Sometimes you don’t want to share something broadly because it’s too personal or sensitive, and sometimes you just don’t want to bug everyone. In both cases, services that help you share more narrowly and with more precision can “win your business” when you otherwise would have shared reluctantly or not at all.</p>
<p>Foursquare, Path, and Google+ (and email) are all good examples of this. Sharing your current location can be both sensitive and noisy, but on foursquare most people maintain a smaller and more highly trusted list of friends, and everyone there has also chosen to use the service for this purpose. Thus it wins on both privacy and relevance, whereas Facebook Places has largely failed to compete, in part because people have <em>too many</em> friends there. Similarly, Path encourages you to only share to your closest set of friends and family, and thus you feel free to share more, both because you trust who’s seeing your information, and because they’re less likely to feel you’re “spamming them” if they&#8217;re close to you. And by letting you share to different circles (or publicly) each time you post, Google+ lets you tune both the privacy and relevance of your audience each time you have something to say. Google+ users routinely post to several distinct audiences, showing that we all have more to say if we can easily control who’s listening.</p>
<p><strong>Sharing more tailored/beautiful content</strong> is in theory orthogonal to audience size/control, but it’s another instance in which smaller services often have an advantage, because they can specialize in helping users quickly craft and share content that is richer and more visually delightful than they could easily do on a larger and more generic social network. This is an effective axis for competition in sharing because we all want to express ourselves in a way that’s compelling and likely to evoke <strong>delight</strong> and <strong>reaction</strong> from our friends/followers. So services that help you look good can again “win your business” when you otherwise would have shared something generic or not at all.</p>
<p>Instagram and Tumblr jump out from my list above as services that have attracted users because they help you “look good for less”, but actually all five services have succeeded here to some extent. A foursquare check-in has rich metadata about the place you’re visiting, so it’s a more meaningful way to share than simply saying “I’m eating at Cafe Gibraltar”. Instagram lets you apply cool filters to your photos, and more importantly IMO, constrains the sharing experience to only be a single photo with a short caption (thus further encouraging this type of sharing). Path just looks beautiful end-to-end, which entices you to live in their world, and they also add lovely touches like displaying the local weather next to your shared moments or letting you easily share when you went to bed and woke up (and how much sleep you got). Again, these are all things you could share elsewhere, but it just feels better and more natural on these more tailored services. Tumblr is “just another blogging tool” in some ways, but its beautiful templates and its focus on quickly reblogging other content along with a quick message has led to an explosion of people starting up their own “tumblelogs”. And on Google+, one of the reasons a thriving photography community quickly formed is just that photos are displayed in a more compelling and engaging way than elsewhere.</p>
<p><strong>The future of social networking</strong> will be largely about making it <em>easier</em> to share <em>richer</em> content with a more <em>relevant</em> audience. Some already decry the current “information overload” on social networks, but I would argue that (a) many/most of the meaningful moments in the lives of people I care about are still going un-shared (mainly because it’s too hard), (b) the feeling of overload largely comes from the low “signal-to-noise ratio” of posts shared today (owing to the lack of easy audience targeting), and (c) the content shared today is largely generic and homogeneous, thus it’s harder to pick out the interesting bits at the times when its most relevant. But as long as entrepreneurs can think up new ways to make it easier to capture and share the moments of your life (and the things you find interesting) in beautiful, high fidelity, and make it easier to share those moments with just the right people at the right time, we’ll soon look back on the current state of social networking with the same wistful bemusement we cast today on brick-sized feature phones and black-and-white personal computers. Let’s get to it!
<div class="social4i" style="height:29px;">
<div class="social4in" style="height:29px;float: left;">
<div class="socialicons s4twitter" style="float:left;margin-right: 10px;"><a href="https://twitter.com/share" data-url="http://josephsmarr.com/2012/01/05/winning-market-share-in-the-sharing-market/" data-counturl="http://josephsmarr.com/2012/01/05/winning-market-share-in-the-sharing-market/" data-text="Winning Market Share in the Sharing Market" class="twitter-share-button" data-count="horizontal" data-via="jsmarr"></a></div>
<div class="socialicons s4fblike" style="float:left;margin-right: 10px;">
<div id="fb-root"></div>
<p><fb:like href="http%3A%2F%2Fjosephsmarr.com%2F2012%2F01%2F05%2Fwinning-market-share-in-the-sharing-market%2F" send="false" layout="button_count" width="100" height="21" show_faces="false" font=""></fb:like></div>
<div class="socialicons s4plusone" style="float:left;margin-right: 10px;"><g:plusone size="medium" href="http://josephsmarr.com/2012/01/05/winning-market-share-in-the-sharing-market/" count="true"></g:plusone></div>
</div>
<div style="clear:both"></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://josephsmarr.com/2012/01/05/winning-market-share-in-the-sharing-market/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Fighting for the Future of the Social Web: Selling Out and Opening Up (OSCON 2011)</title>
		<link>http://josephsmarr.com/2011/07/27/fighting-for-the-future-of-the-social-web-selling-out-and-opening-up-oscon-2011/</link>
		<comments>http://josephsmarr.com/2011/07/27/fighting-for-the-future-of-the-social-web-selling-out-and-opening-up-oscon-2011/#comments</comments>
		<pubDate>Thu, 28 Jul 2011 00:34:17 +0000</pubDate>
		<dc:creator>joseph</dc:creator>
				<category><![CDATA[Open Social Web]]></category>
		<category><![CDATA[Papers and Talks]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://josephsmarr.com/?p=94</guid>
		<description><![CDATA[Fighting for the Future of the Social Web: Selling Out and Opening Up O&#8217;Reilly Open Source Convention (OSCON) 2011 Portland, OR July 27, 2011 (Note: some of the footer fonts are messed up on slideshare, sorry.) Download PPT (12.5 MB) A year and a half after joining Google, and a year after my last talk [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Fighting for the Future of the Social Web: Selling Out and Opening Up</strong><br />
<a href="http://www.oscon.com/oscon2011/public/schedule/detail/19106">O&#8217;Reilly Open Source Convention (OSCON) 2011</a><br />
Portland, OR<br />
July 27, 2011</p>
<div style="width:425px" id="__ss_10632259"><em>(Note: some of the footer fonts are messed up on slideshare, sorry.)</em><iframe src="http://www.slideshare.net/slideshow/embed_code/10632259?rel=0" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe></div>
<p><a href="http://www.slideshare.net/jsmarr/fighting-for-the-future-of-the-social-web-selling-out-and-opening-up-10632259/download">Download PPT</a> (12.5 MB)</p>
<p>A year and a half after <a href="http://josephsmarr.com/2009/12/18/joseph-smarr-has-new-work-info%E2%80%A6/">joining Google</a>, and a year after <a href="http://josephsmarr.com/2010/06/04/bridging-the-islands-building-fluid-social-experiences-across-websites-google-io-2010/">my last talk</a> on the Social Web, I returned to OSCON (one of my favorite conferences, which I&#8217;ve been <a href="http://josephsmarr.com/2007/07/25/high-performance-javascript-oscon-2007/">speaking</a> <a href="http://josephsmarr.com/2007/01/27/cross-site-ajax-oscon-2006/">at</a> for over half a decade now!) to reflect on the progress we&#8217;ve collectively made (and haven&#8217;t made) to open up the social web. I covered the latest developments in OpenID, OAuth, Portable Contacts, and related open web standards, mused about the challenges we&#8217;re still facing to adoption and ease-of-use and what to do about them, and considered what changes we should expect going forward now that many of the formerly independent open social web enthusiasts (myself included) now work for larger companies.</p>
<p>Not to spoil the punchline, but if you know me at all it won&#8217;t surprise you to learn that I&#8217;m still optimistic about the future! <img src='http://josephsmarr.com/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />
<div class="social4i" style="height:29px;">
<div class="social4in" style="height:29px;float: left;">
<div class="socialicons s4twitter" style="float:left;margin-right: 10px;"><a href="https://twitter.com/share" data-url="http://josephsmarr.com/2011/07/27/fighting-for-the-future-of-the-social-web-selling-out-and-opening-up-oscon-2011/" data-counturl="http://josephsmarr.com/2011/07/27/fighting-for-the-future-of-the-social-web-selling-out-and-opening-up-oscon-2011/" data-text="Fighting for the Future of the Social Web: Selling Out and Opening Up (OSCON 2011)" class="twitter-share-button" data-count="horizontal" data-via="jsmarr"></a></div>
<div class="socialicons s4fblike" style="float:left;margin-right: 10px;">
<div id="fb-root"></div>
<p><fb:like href="http%3A%2F%2Fjosephsmarr.com%2F2011%2F07%2F27%2Ffighting-for-the-future-of-the-social-web-selling-out-and-opening-up-oscon-2011%2F" send="false" layout="button_count" width="100" height="21" show_faces="false" font=""></fb:like></div>
<div class="socialicons s4plusone" style="float:left;margin-right: 10px;"><g:plusone size="medium" href="http://josephsmarr.com/2011/07/27/fighting-for-the-future-of-the-social-web-selling-out-and-opening-up-oscon-2011/" count="true"></g:plusone></div>
</div>
<div style="clear:both"></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://josephsmarr.com/2011/07/27/fighting-for-the-future-of-the-social-web-selling-out-and-opening-up-oscon-2011/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bridging the islands: Building fluid social experiences across websites (Google I/O 2010)</title>
		<link>http://josephsmarr.com/2010/06/04/bridging-the-islands-building-fluid-social-experiences-across-websites-google-io-2010/</link>
		<comments>http://josephsmarr.com/2010/06/04/bridging-the-islands-building-fluid-social-experiences-across-websites-google-io-2010/#comments</comments>
		<pubDate>Fri, 04 Jun 2010 21:58:44 +0000</pubDate>
		<dc:creator>joseph</dc:creator>
				<category><![CDATA[Open Social Web]]></category>
		<category><![CDATA[Papers and Talks]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://josephsmarr.com/?p=82</guid>
		<description><![CDATA[Bridging the islands: Building fluid social experiences across websitesGoogle I/O 2010San Francisco, CAMay 19, 2010 View talk and download slides as PDF My third year speaking at Google I/O, and my first as a Googler! I teamed up with fellow Googler John Panzer, and together we demonstrated how far open standards have come in allowing [...]]]></description>
			<content:encoded><![CDATA[<p><span style="font-family: Verdana, Tahoma, Arial, sans-serif; font-size: 12px; color: #303030;"><strong>Bridging the islands: Building fluid social experiences across websites<br style="padding: 0px; margin: 0px;" /></strong><a style="background-color: inherit; color: #286ea0; font-weight: bold; padding: 0px; margin: 0px;" href="http://code.google.com/events/io/2010/sessions/building-fluid-social-experiences-across-websites.html">Google I/O 2010</a><br style="padding: 0px; margin: 0px;" />San Francisco, CA<br style="padding: 0px; margin: 0px;" />May 19, 2010</span></p>
<p><span style="font-family: Verdana, Tahoma, Arial, sans-serif; font-size: 12px; color: #303030;"><a href="http://code.google.com/events/io/2010/sessions/building-fluid-social-experiences-across-websites.html">View talk and download slides as PDF</a></span></p>
<p><span style="font-family: Verdana, Tahoma, Arial, sans-serif; font-size: 12px; color: #303030;">My <a href="http://josephsmarr.com/2009/05/29/the-social-web-an-implementers-guide-google-io-2009/">third</a> <a href="http://josephsmarr.com/2008/05/30/opensocial-openid-and-oauth-oh-my-google-io/">year</a> speaking at Google I/O, and my <a href="http://code.google.com/events/io/2010/sessions/building-fluid-social-experiences-across-websites.html">first</a> as a Googler! I teamed up with fellow Googler John Panzer, and together we demonstrated how far open standards have come in allowing developers to build rich cross-site social integrations. From frictionless sign-up using OpenID, OAuth, and webfinger to finding your friends with Portable Contacts and microformats to sharing rich activities and holding real-time distributed conversations with ActivityStrea.ms, PubSubHubBub, and salmon, it really is remarkable how much progress we&#8217;ve made as a community. And it still feels like we&#8217;re just getting started, with the real payoff right around the corner!</span></p>
<p><span style="font-family: Verdana, Tahoma, Arial, sans-serif; font-size: 12px; color: #303030;">We took a literal approach to our concept of &#8220;bridging the islands&#8221; by telling a story of two imaginary islanders, who meet while on vacation and fall in love. They struggle with all the same problems that users of today&#8217;s social web do&#8211;the pain of immigrating to a new place, the pain of being able to find your friends once they&#8217;ve moved, and the pain of being able to stay in touch with the people you care about, even when you don&#8217;t all live in the same place. Besides having fun stretching the metaphor and making pretty slides (special thanks to Chris Messina for his artistic inspiration and elbow grease!), the point is that these are all fundamental problems, and just as we created technology to solve them in the real world, so must be solve them on the Social Web. </span></p>
<p><span style="font-family: Verdana, Tahoma, Arial, sans-serif; font-size: 12px; color: #303030;"><a href="http://code.google.com/events/io/2010/sessions/open-and-social-web.html">Chris&#8217;s talk at I/O</a> told this story at a high level and with additional color, while we dove more into the technology that makes it possible. Make sure to check out both talks, and I hope they will both inspire and inform you&#8211;whether as a developer or a user&#8211;to help us complete this important work as a community!</span></p>
<p><span style="font-family: Verdana, Tahoma, Arial, sans-serif; font-size: 12px; color: #303030;"><br />
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="560" height="340" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/Vxj4DTGKdj0&amp;hl=en_US&amp;fs=1&amp;" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="560" height="340" src="http://www.youtube.com/v/Vxj4DTGKdj0&amp;hl=en_US&amp;fs=1&amp;" allowscriptaccess="always" allowfullscreen="true"></embed></object><br />
</span>
<div class="social4i" style="height:29px;">
<div class="social4in" style="height:29px;float: left;">
<div class="socialicons s4twitter" style="float:left;margin-right: 10px;"><a href="https://twitter.com/share" data-url="http://josephsmarr.com/2010/06/04/bridging-the-islands-building-fluid-social-experiences-across-websites-google-io-2010/" data-counturl="http://josephsmarr.com/2010/06/04/bridging-the-islands-building-fluid-social-experiences-across-websites-google-io-2010/" data-text="Bridging the islands: Building fluid social experiences across websites (Google I/O 2010)" class="twitter-share-button" data-count="horizontal" data-via="jsmarr"></a></div>
<div class="socialicons s4fblike" style="float:left;margin-right: 10px;">
<div id="fb-root"></div>
<p><fb:like href="http%3A%2F%2Fjosephsmarr.com%2F2010%2F06%2F04%2Fbridging-the-islands-building-fluid-social-experiences-across-websites-google-io-2010%2F" send="false" layout="button_count" width="100" height="21" show_faces="false" font=""></fb:like></div>
<div class="socialicons s4plusone" style="float:left;margin-right: 10px;"><g:plusone size="medium" href="http://josephsmarr.com/2010/06/04/bridging-the-islands-building-fluid-social-experiences-across-websites-google-io-2010/" count="true"></g:plusone></div>
</div>
<div style="clear:both"></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://josephsmarr.com/2010/06/04/bridging-the-islands-building-fluid-social-experiences-across-websites-google-io-2010/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Implementing PubSubHubbub subscriber support: A step-by-step guide</title>
		<link>http://josephsmarr.com/2010/03/01/implementing-pubsubhubbub-subscriber-support-a-step-by-step-guide/</link>
		<comments>http://josephsmarr.com/2010/03/01/implementing-pubsubhubbub-subscriber-support-a-step-by-step-guide/#comments</comments>
		<pubDate>Mon, 01 Mar 2010 21:25:17 +0000</pubDate>
		<dc:creator>joseph</dc:creator>
				<category><![CDATA[Open Social Web]]></category>
		<category><![CDATA[Plaxo]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://josephsmarr.com/2010/03/01/implementing-pubsubhubbub-subscriber-support-a-step-by-step-guide/</guid>
		<description><![CDATA[One of the last things I did before leaving Plaxo was to implement PubSubHubbub (PuSH) subscriber support, so that any blogs which ping a PuSH hub will show up almost instantly in pulse after being published. It&#8217;s easy to do (you don&#8217;t even need a library!), and it significantly improves the user experience while simultaneously [...]]]></description>
			<content:encoded><![CDATA[<p>One of the last things I did before leaving Plaxo was to implement <a href="http://code.google.com/p/pubsubhubbub/">PubSubHubbub</a> (PuSH) subscriber support, so that any blogs which ping a PuSH hub will show up almost instantly in pulse after being published. It&#8217;s easy to do (you don&#8217;t even need a library!), and it significantly improves the user experience while simultaneously reducing server load on your site and the sites whose feeds you&#8217;re crawling. At the time, I couldn&#8217;t find any good tutorials for how to implement PuSH subscriber support (add a comment if you know of any), so here&#8217;s how I did it. (Note: depending on your needs, you might find it useful instead to use a third-party service like <a href="http://www.gnip.com/">Gnip</a> to do this.)</p>
<p>My assumption here is that you&#8217;ve already got a <strong>database of feeds</strong> you&#8217;re subscribing to, but that you&#8217;re <strong>currently just polling</strong> them all periodically to look for new content. This tutorial will help you &#8220;<strong>gracefully upgrade</strong>&#8221; to support PuSH-enabled blogs without rewriting your fundamental polling infrastructure. At the end, I&#8217;ll suggest a more radical approach that is probably better overall if you can afford a bigger rewrite of your crawling engine.</p>
<p>The steps to add PuSH subscriber support are as follows:</p>
<ol>
<li>Identify PuSH-enabled blogs <span style="font-weight: bold">extract </span>their hub and topic</li>
<li>Lazily <span style="font-weight: bold">subscribe </span>to PuSH-enabled blogs as you discover them</li>
<li><span style="font-weight: bold">Verify </span>subscription requests from the hub as you make them</li>
<li>Write an endpoint to <span style="font-weight: bold">receive pings</span> from the hub as new content is published</li>
<li>Get the latest <span style="font-weight: bold">content </span>from updated blogs as you receive pings</li>
<li><span style="font-weight: bold">Unsubscribe </span>from feeds when they&#8217;re deleted from your system</li>
</ol>
<p><u>1. Identify PuSH-enabled blogs <span style="font-weight: bold">extract </span>their hub and topic</u></p>
<p>When crawling a feed normally, you can look for some extra metadata in the XML that tells you this blog is PuSH-enabled. Specifically, you want to look for two links: the &#8220;hub&#8221; (the URL of the hub that the blog pings every time it has new content, which you in turn communicate with to subscribe and receive pings when new content is published), and the &#8220;self&#8221; (the canonical URL of the blog you&#8217;re subscribing to, which is referred to as the &#8220;topic&#8221; you&#8217;re going to subscribe to from the hub).</p>
<p>A useful test blog to use while building PuSH subscriber support is <a href="http://pubsubhubbub-example-app.appspot.com/">http://pubsubhubbub-example-app.appspot.com/</a>, since it lets anyone publish new content. If you view source on that page, you&#8217;ll notice the standard RSS auto-discovery tag that tells you where to find the blog&#8217;s feed:</p>
<p><code>&lt;link title="PubSubHubbub example app" type="application/atom+xml" rel="alternate" /></code></p>
<p>And if you view source on <a href="http://pubsubhubbub-example-app.appspot.com/feed">http://pubsubhubbub-example-app.appspot.com/feed</a>, you&#8217;ll see the two PuSH links advertised underneath the root <code>feed</code> tag:</p>
<p><code>&lt;link type="application/atom+xml" title="PubSubHubbub example app" rel="self" /><br />
&lt;link rel="hub"  href="http://pubsubhubbub.appspot.com/" /></code></p>
<p>You can see that the &#8220;self&#8221; link is the same as the URL of the feed that you&#8217;re already using, and the &#8220;hub&#8221; link is to the free hub being hosted on AppEngine at <code>http://pubsubhubbub.appspot.com/</code>. In both cases, you want to look for a link tag under the root feed tag, match the appropriate rel-value (keeping in mind that rel-attributes can have multiple, space-separated values, e.g. <code>rel="self somethingelse"</code>, so split the rel-value on spaces and then look for the specific matching rel-value), and then extract the corresponding href-value from that link tag. Note that the example above is an ATOM feed; in RSS feeds, you generally have to look for <code>atom:link</code> tags under the <code>channel</code> tag under the root <code>rss</code> tag, but the rest is the same.</p>
<p>Once you have the hub and self links for this blog (assuming the blog is PuSH-enabled), you&#8217;ll want to store the self-href (aka the &#8220;topic&#8221;) with that feed in your database so you&#8217;ll know whether you&#8217;ve subscribed to it, and, if so, whether the topic has changed since you last subscribed.</p>
<p><u>2.  Lazily <strong>subscribe </strong>to PuSH-enabled blogs as you discover them</u></p>
<p>When you&#8217;re crawling a feed and you notice it&#8217;s PuSH-enabled, check your feed database to see if you&#8217;ve got a stored PuSH-topic for that feed, and if so, whether the current topic is the same as your stored value. If you don&#8217;t have any stored topic, or if the current topic is different, you&#8217;ll want to talk to that blog&#8217;s PuSH hub and initiate a subscription so that you can receive real-time updates when new content is published to that blog. By storing the PuSH-topic per-feed, you can effectively &#8220;lazily subscribe&#8221; to all PuSH-enabled blogs by continuing to regularly poll and crawl them as you currently do, and adding PuSH subscriptions as you find them. This means you don&#8217;t have to do any large one-time migration over to PuSH, and you can automatically keep up as more blogs become PuSH-enabled or change their topics over time. (Depending on your crawling infrastructure, you can either initiate subscriptions as soon as you find the relevant tags, or you can insert an asynchronous job to initiate the subscription so that some other part of your system can handle that later without slowing down your crawlers.)</p>
<p>To subscribe to a PuSH-enabled blog, just send an HTTP POST to its hub URL and provide the following POST parameters:</p>
<ul>
<li><code>hub.callback</code> = [the URL of your endpoint for receiving pings, which we'll build in step 4]</li>
<li><code>hub.mode</code> = <code>subscribe</code></li>
<li><code>hub.topic</code> = [the self-link / topic of the feed you're subscribing to, which you extracted in step 1]</li>
<li><code>hub.verify</code> = <code>async</code> [means the hub will separately call you back to verify this subscription]</li>
<li><code>hub.verify_token</code> = [a hard-to-guess token associated with this feed, which the hub will echo back to you to prove it's a real subscription verification]</li>
</ul>
<p>For the <code>hub.callback</code> URL, it&#8217;s probably best to include the internal database ID of the feed you&#8217;re subscribing to, so it&#8217;s easy to look up that feed when you receive future update pings. Depending on your setup, this might be something like <code>http://yoursite.com/push/update?feed_id=123</code> or <code>http://yoursite.com/push/update/123</code>. Another advantage of this technique is that it makes it relatively hard to guess what the update URL is for an arbitrary blog, in case an evil site wanted to send you fake updates. If you want even more security, you could put some extra token in the URL that&#8217;s different per-feed, or you could use the <code>hub.secret</code> mechanism when subscribing, which will cause the hub to send you a signed verification header with every ping, but that&#8217;s beyond the scope of this tutorial.</p>
<p>For the <code>hub.verify_token</code>, the simplest thing would just be to pick a secret word (e.g. &#8220;<code>MySekritVerifyToken</code>&#8220;) and always use that, but an evil blog could use its own hub and quickly discover that secret. So a better idea is to do something like take the HMAC-SHA1 of the topic URL along with some secret salt you keep internally. This way, the <code>hub.verify_token</code> value is feed-specific, but it&#8217;s easy to recompute when you receive the verification.</p>
<p>If your subscription request is successful, the hub will respond with an HTTP 202 &#8220;Accepted&#8221; code, and will then proceed to send you a verification request for this subscription at your specified callback URL.</p>
<p><u>3. <strong>Verify </strong>subscription requests from the hub as you make them</u></p>
<p>Shortly after you send your subscription request to the hub, it will call you back at the <code>hub.callback</code> URL you specified with an HTTP GET request containing the following query parameters:</p>
<ul>
<li><code>hub.mode</code> = <code>subscribe</code></li>
<li><code>hub.topic</code> = [the self-link / topic of the URL you requested a subscription for]</li>
<li><code>hub.challenge</code> = [a random string to verify this verification that you have to echo back in the response to acknowledge verification]</li>
<li><code>hub.verify_token</code> = [the value you sent in <code>hub.verify_token</code> during your subscription request]</li>
</ul>
<p>Since the endpoint you receive this verification request is the same one you&#8217;ll receive future update pings on, your logic has to first look for <code>hub.mode=subscribe</code>, and if so, verify that the hub sent the proper <code>hub.verify_token</code> back to you, and then just dump out the <code>hub.challenge</code> value as the response body of your page (with a standard HTTP 200 response code). Now you&#8217;re officially subscribed to this feed, and will receive update pings when the blog publishes new content.</p>
<p>Note that hubs may periodically re-verify that you still want a subscription to this feed. So you should make sure that if the hub makes a similar verification request out-of-the-blue in the future, you respond the same way you did the first time, providing you indeed are still interested in that feed. A good way to do this is just to look up the feed every time you get a verification request (remember, you build the feed&#8217;s ID into your callback URL), and if you&#8217;ve since deleted or otherwise stopped caring about that feed, return an HTTP 404 response instead so the hub will know to stop pinging you with updates.</p>
<p><u>4. Write an endpoint to <strong>receive pings</strong> from the hub as new content is published</u></p>
<p>Now you&#8217;re ready for the pay-out&#8211;magically receiving pings from the ether every time the blog you&#8217;ve subscribed to has new content! You&#8217;ll receive inbound requests to your specified callback URL without any additional query parameters added (i.e. you&#8217;ll know it&#8217;s a ping and not a verification because there won&#8217;t be any <code>hub.mode</code> parameter included). Instead, the new entries of the subscribed feed will be included directly in the POST body of the request, with a request Content-Type of <code>application/atom+xml</code> for ATOM feeds and <code>application/rss+xml</code> for RSS feeds. Depending on your programming language of choice, you&#8217;ll need to figure out how to extract the raw POST body contents. For instance, in PHP you would <code>fopen</code> the special filename <code>php://input</code> to read it.</p>
<p><u>5. Get the latest <strong>content </strong>from updated blogs as you receive pings</u></p>
<p>The ping is really telling you two things: 1) this blog has updated content, and 2) here it is. The advantage of providing the content directly in the ping (a so-called &#8220;<a href="http://techcrunch.com/2009/09/09/rsscloud-vs-pubsubhubbub-why-the-fat-pings-win/">fat ping</a>&#8220;) is so that the subscriber doesn&#8217;t have to go re-crawl the feed to get the updated content. Not only is this a performance savings (especially when you consider that lots of subscribers may get pings for a new blog post at roughly the same time, and they might otherwise all crawl that blog at the same time for the new contents; the so-called &#8220;thundering herd&#8221; problem), it&#8217;s also a form of robustness since some blogging systems take a little while to update their feeds when a new post is published (especially for large blogging systems that have to propagate changes across multiple data-centers or update caching tiers), so it&#8217;s possible you&#8217;ll receive a ping before the content is available to crawl directly. For these reasons and more, it&#8217;s definitely a best-practice to consume the fat ping directly, rather than just using it as a hint to go crawl the blog again (i.e. treating it as a &#8220;light ping&#8221;).</p>
<p>That being said, most crawling systems are designed just to poll URLs and look for new data, so it may be easier to start out by taking the &#8220;light ping&#8221; route. In other words, when you receive a PuSH ping, look up the feed ID from the URL of the request you&#8217;re handling, and assuming that feed is still valid, just schedule it to crawl ASAP. That way, you don&#8217;t have to change the rest of your crawling infrastructure; you just treat the ping as a hint to crawl now instead of waiting for the next regular polling interval. While sub-optimal, in my experience this works pretty well and is very easy to implement. (It&#8217;s certainly a major improvement over just polling with no PuSH support!) If you&#8217;re worried about crawling before the new content is in the feed, and you don&#8217;t mind giving up a bit of speed, you can schedule your crawler for &#8220;in N seconds&#8221; instead of ASAP, which in practice will allow a lot of slow-to-update feeds to catch up before you crawl them.</p>
<p>Once you&#8217;re ready to handle the fat pings directly, extract the updated feed entries from the POST body of the ping (the payload is essentially an exact version of the full feed you&#8217;d normally fetch, except it only contains entries for the new content), and ingest it however you normally ingest new blog content. In fact, you can go even further and make PuSH the <em>default</em> way to ingest blog content&#8211;change your polling code to act as a &#8220;fake PuSH proxy&#8221; and emit PuSH-style updates whenever it finds new entries. Then your core feed-ingesting code can just process all your updated entries in the same way, whether they came from a hub or your polling crawlers.</p>
<p>However you handle the pings, once you find that things are working reliably, you can change the polling interval for PuSH-enabled blogs to be much slower, or even turn it off completely, if you&#8217;re not worried about ever missing a ping. In practice, slow polling (e.g. once a day) is probably still a good hedge against the inevitable clogs in the internet&#8217;s tubes.</p>
<p><u>6. <strong>Unsubscribe </strong>from feeds when they&#8217;re deleted from your system</u></p>
<p>Sometimes users will delete their account on your system or unhook one of their feeds from their account. To be a good citizen, rather than just waiting for the next time the hub sends a subscription verification request to tell it you no longer care about this feed, you should send the hub an unsubscribe request when you know the feed is no longer important to you. The process is identical to subscribing to a feed (as described in steps 2 and 3), except you use &#8220;<code>unsubscribe</code>&#8221; instead of &#8220;<code>subscribe</code>&#8221; for the <code>hub.mode</code> values in all cases.</p>
<p><u>Testing your implementation</u></p>
<p>Now that you know all the steps needed to implement PuSH subscriber support, it&#8217;s time to test your code in the wild. Probably the easiest way is to hook up that <a href="http://pubsubhubbub-example-app.appspot.com/">http://pubsubhubbub-example-app.appspot.com/</a> feed, since you can easily add content it to it to test pings, and it&#8217;s known to have valid hub-discovery metadata. But you can also practice with any blog that is PuSH-enabled (perhaps your shiny new Google Buzz public posts feed?). In any case, schedule it to be crawled normally, and verify that it correctly extracts the hub-link and self-link and adds the self-link to your feed database.</p>
<p>The first time it finds these links, it should trigger a subscription request. (On subsequent crawls, it shouldn&#8217;t try to subscribe again, since the topic URL hasn&#8217;t changed. ) Verify that you&#8217;re sending a request to the hub that includes all the necessary parameters, and verify that it&#8217;s sending you back a 202 response. If it&#8217;s not working, carefully check that you&#8217;re sending all the right parameters.</p>
<p>Next, verify that upon sending a subscription request, you&#8217;ll soon get an inbound verification request from the hub. Make sure you detect requests to your callback URL with <code>hub.mode=subscribe</code>, and that you are checking the <code>hub.verify_token</code> value against the value you sent in the subscription request, and then that you&#8217;re sending the <code>hub.challenge</code> value as your response body. Unfortunately, it&#8217;s usually not easy to inspect the hub directly to confirm that it has properly verified your subscription, but hopefully some hubs will start providing site-specific dashboards to make this process more transparent. In the meantime, the best way to verify that things worked properly is to try making test posts to the blog and looking for incoming pings.</p>
<p>So add a new post on the example blog, or write a real entry on your PuSH-enabled blog of choice, and look in your server logs to make sure a ping came in. Depending on the hub, the ping may come nearly instantaneously or after a few seconds. If you don&#8217;t see it after several seconds, something is probably wrong, but try a few posts to make sure you didn&#8217;t just miss it. Look at the specific URL that the hub is calling on your site, and verify that it has your feed ID in the URL, and that it does indeed match the feed that just published new content. If you&#8217;re using the &#8220;light ping&#8221; model, check that you scheduled your feed to crawl ASAP. If you&#8217;re using the &#8220;fat ping&#8221; model, check that you correctly ingested the new content that was in the POST body of the ping.</p>
<p>Once everything appears to be working, try un-hooking your test feed (and/or deleting your account) and verify that it triggers you to send an unsubscribe request to the hub, and that you properly handle the subsequent unsubscribe verification request from the hub.</p>
<p>If you&#8217;ve gotten this far, congratulations! You are now part of the real-time-web! Your users will thank you for making their content show up more quickly on your site, and the sites that publish those feeds will thank you for not crawling them as often, now that you can just sit back and wait for updates to be PuSH-ed to you. And I and the rest of the community will thank you for supporting open standards for a decentralized social web!</p>
<p><em>(Thanks to <a href="http://www.google.com/profiles/bslatkin">Brett Slatkin</a> for providing feedback on a draft of this post!)</em>
<div class="social4i" style="height:29px;">
<div class="social4in" style="height:29px;float: left;">
<div class="socialicons s4twitter" style="float:left;margin-right: 10px;"><a href="https://twitter.com/share" data-url="http://josephsmarr.com/2010/03/01/implementing-pubsubhubbub-subscriber-support-a-step-by-step-guide/" data-counturl="http://josephsmarr.com/2010/03/01/implementing-pubsubhubbub-subscriber-support-a-step-by-step-guide/" data-text="Implementing PubSubHubbub subscriber support: A step-by-step guide" class="twitter-share-button" data-count="horizontal" data-via="jsmarr"></a></div>
<div class="socialicons s4fblike" style="float:left;margin-right: 10px;">
<div id="fb-root"></div>
<p><fb:like href="http%3A%2F%2Fjosephsmarr.com%2F2010%2F03%2F01%2Fimplementing-pubsubhubbub-subscriber-support-a-step-by-step-guide%2F" send="false" layout="button_count" width="100" height="21" show_faces="false" font=""></fb:like></div>
<div class="socialicons s4plusone" style="float:left;margin-right: 10px;"><g:plusone size="medium" href="http://josephsmarr.com/2010/03/01/implementing-pubsubhubbub-subscriber-support-a-step-by-step-guide/" count="true"></g:plusone></div>
</div>
<div style="clear:both"></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://josephsmarr.com/2010/03/01/implementing-pubsubhubbub-subscriber-support-a-step-by-step-guide/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>The Social Web: An Implementer&#8217;s Guide (Google I/O 2009)</title>
		<link>http://josephsmarr.com/2009/05/29/the-social-web-an-implementers-guide-google-io-2009/</link>
		<comments>http://josephsmarr.com/2009/05/29/the-social-web-an-implementers-guide-google-io-2009/#comments</comments>
		<pubDate>Fri, 29 May 2009 17:14:32 +0000</pubDate>
		<dc:creator>joseph</dc:creator>
				<category><![CDATA[Open Social Web]]></category>
		<category><![CDATA[Papers and Talks]]></category>
		<category><![CDATA[Plaxo]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://josephsmarr.com/2009/05/29/the-social-web-an-implementers-guide-google-io-2009/</guid>
		<description><![CDATA[The Social Web: An Implementer&#8217;s Guide Google I/O 2009 San Francisco, CA May 28, 2009 The Social Web: An Implementer&#39;s Guide (Google I/O 2009) Download PPT (7.3 MB) Google invited me back for a second year in a row to speak at their developer conference about the state-of-the-art of opening up the social web. While [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://code.google.com/events/io/sessions/SocialWebImplementorsGuide.html"><strong>The Social Web: An Implementer&#8217;s Guide</strong></a><br />
<a href="http://code.google.com/events/io/">Google I/O 2009</a><br />
San Francisco, CA<br />
May 28, 2009</p>
<p>
<div style="width:425px;text-align:left" id="__ss_1507288"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/jsmarr/the-social-web-an-implementers-guide-google-io-2009?type=presentation" title="The Social Web: An Implementer&#39;s Guide (Google I/O 2009)">The Social Web: An Implementer&#39;s Guide (Google I/O 2009)</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=googleio-smarr-2009-090529121903-phpapp01&#038;rel=0&#038;stripped_title=the-social-web-an-implementers-guide-google-io-2009" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=googleio-smarr-2009-090529121903-phpapp01&#038;rel=0&#038;stripped_title=the-social-web-an-implementers-guide-google-io-2009" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object></div>
</p>
<p><a href="http://josephsmarr.com/papers/GoogleIO-Smarr-2009.ppt">Download PPT</a> (7.3 MB)</p>
<p><a href="http://code.google.com/events/io"><img height="36" align="right" width="187" src="http://code.google.com/events/io/images/io2009-sm.png" /></a>Google invited me back for a <a href="http://josephsmarr.com/2008/05/30/opensocial-openid-and-oauth-oh-my-google-io/">second year</a> in a row to speak at their developer conference about the state-of-the-art of opening up the social web. While my talk last year laid out the promise and vision of an interoperable social web ecosystem, this year I wanted to show all the concrete progress we&#8217;ve made as an industry in achieving that goal. So <a href="http://josephsmarr.com/papers/GoogleIO-Smarr-2009.ppt">my talk</a> was full of demos&#8211;signing up for Plaxo with an existing Gmail account in just two clicks, using MySpaceID to jump into a niche music site without a separate sign-up step, ending &#8220;re-friend madness&#8221; by honoring Facebook friend connections on Plaxo (via Facebook Connect), killing the &#8220;password anti-pattern&#8221; with user-friendly contact importers from a variety of large sites (demonstrated with FriendFeed), and sharing activity across sites using Google FriendConnect and Plaxo. Doing live demos is always a risky proposition, especially when they involve cross-site interop, but happily all the demos worked fine and the talk was a big success!</p>
<p>I began my talk by observing that the events of the last year has made it clear: The web is going social, and the social web is going open. By the end of my talk, having showed so many mainstream sites with deep user-friendly and user-friendly interoperability, I decided to go a step further and declare: <strong>The web is now social, and the social web is now open</strong>. You don&#8217;t have to wait any longer to start reaping the benefits. It&#8217;s time to dive in.
</p>
<div class="social4i" style="height:29px;">
<div class="social4in" style="height:29px;float: left;">
<div class="socialicons s4twitter" style="float:left;margin-right: 10px;"><a href="https://twitter.com/share" data-url="http://josephsmarr.com/2009/05/29/the-social-web-an-implementers-guide-google-io-2009/" data-counturl="http://josephsmarr.com/2009/05/29/the-social-web-an-implementers-guide-google-io-2009/" data-text="The Social Web: An Implementer&#8217;s Guide (Google I/O 2009)" class="twitter-share-button" data-count="horizontal" data-via="jsmarr"></a></div>
<div class="socialicons s4fblike" style="float:left;margin-right: 10px;">
<div id="fb-root"></div>
<p><fb:like href="http%3A%2F%2Fjosephsmarr.com%2F2009%2F05%2F29%2Fthe-social-web-an-implementers-guide-google-io-2009%2F" send="false" layout="button_count" width="100" height="21" show_faces="false" font=""></fb:like></div>
<div class="socialicons s4plusone" style="float:left;margin-right: 10px;"><g:plusone size="medium" href="http://josephsmarr.com/2009/05/29/the-social-web-an-implementers-guide-google-io-2009/" count="true"></g:plusone></div>
</div>
<div style="clear:both"></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://josephsmarr.com/2009/05/29/the-social-web-an-implementers-guide-google-io-2009/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Implementing OAuth is still too hard&#8230; but it doesn&#8217;t have to be</title>
		<link>http://josephsmarr.com/2009/02/17/implementing-oauth-is-still-too-hard-but-it-doesnt-have-to-be/</link>
		<comments>http://josephsmarr.com/2009/02/17/implementing-oauth-is-still-too-hard-but-it-doesnt-have-to-be/#comments</comments>
		<pubDate>Wed, 18 Feb 2009 02:53:43 +0000</pubDate>
		<dc:creator>joseph</dc:creator>
				<category><![CDATA[Open Social Web]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://josephsmarr.com/2009/02/17/implementing-oauth-is-still-too-hard-but-it-doesnt-have-to-be/</guid>
		<description><![CDATA[I recently helped Dave Winer debug his OAuth Consumer code, and the process was more painful than it should have been. (He was trying to write a Twitter app using their beta OAuth support, and since he has his own scripting environment for his OPML editor, there wasn&#8217;t an existing library he could just drop [...]]]></description>
			<content:encoded><![CDATA[<p><img height="239" align="right" width="240" src="http://farm4.static.flickr.com/3312/3289508558_24b0e6c525_m.jpg" />I <a href="http://twitter.com/davewiner/status/1220677355">recently</a> <a href="http://www.scripting.com/stories/2009/02/17/oauthIsWorkingHere.html">helped Dave Winer</a> debug his OAuth Consumer code, and the process was more painful than it should have been. (He was trying to write a Twitter app using <a href="http://www.readwriteweb.com/archives/twitter_oauth_spotted.php">their beta OAuth support</a>, and since he has his own scripting environment for his OPML editor, there wasn&#8217;t an existing library he could just drop in.) Now I&#8217;m a big fan of OAuth&#8211;it&#8217;s a key piece of the <a href="http://josephsmarr.com/2008/11/10/a-new-open-stack-greater-than-the-sum-of-its-parts-internet-identity-workshop-2008b/">Open Stack</a>, and it really does work well once you get it working. I&#8217;ve written both OAuth Provider and Consumer code in multiple languages and integrated with OAuth-protected APIs on over half a dozen sites. I&#8217;ve also helped a lot of developers and companies debug their OAuth implementations and libraries. And the plain truth is this: it&#8217;s empirically way too painful still for first-time OAuth developers to get their code working, and despite the fact that OAuth is a standard, the empirical &#8220;it-just-works-rate&#8221; is way too low.</p>
<p>We in the Open Web community should all be concerned about this, since OAuth is the &#8220;gateway&#8221; to most of the open APIs we&#8217;re building, and quite often this first hurdle is the hardest one in the entire process. That&#8217;s not the &#8220;smooth on-ramp&#8221; we should be striving for here. We can and should do better, and I have a number of suggestions for how to do just that.</p>
<p>To some extent, OAuth will always be &#8220;hard&#8221; in the sense that it&#8217;s crypto&#8211;if you get one little bit wrong, the whole thing doesn&#8217;t work. The theory is, &#8220;yeah it might be hard the first time, but at least you only have to suffer that pain once, and then you can use it everywhere&#8221;. But even that promise falls short because most OAuth libraries and most OAuth providers have (or have had) bugs in them, and there aren&#8217;t good enough debugging, validating, and interop tools available to raise the quality bar without a lot of trial-and-error testing and back-and-forth debugging. I&#8217;m fortunate in that a) I&#8217;ve written and debugged OAuth code so many times that I&#8221;m really good at it now, and b) I personally know developers at most of the companies shipping OAuth APIs, but clearly most developers don&#8217;t have those luxuries, nor should they have to.</p>
<p>After I helped Dave get his code working, he said &#8220;you know, what you manually did for me was perfect. But there should have been a software tool to do that for me automatically&#8221;. He&#8217;s totally right, and I think with a little focused effort, the experience of implementing and debugging OAuth could be a ton better. So here are my suggestions for how to help make implementing OAuth easier. I hope to work on some or all of these in my copious spare time, and I encourage everyone that cares about OAuth and the Open Stack to pitch in if you can!</p>
<ul><strong> 	</strong></p>
<li><strong>Write more recipe-style tutorials</strong> that take developers step-by-step through the process of building a simple OAuth Consumer that works with a known API in a bare-bones, no-fluff fashion. There are some <a href="http://www.hueniverse.com/hueniverse/2008/10/beginners-gui-1.html">good tutorials</a> out there, but they tend to be longer on theory and shorter on &#8220;do this, now do this, now you should see that, &#8230;&#8221;, which is what developers need most to get up and running fast. I&#8217;ve written a couple such recipes so far&#8211;one for <a href="http://www.plaxo.com/api/openid_recipe">becoming an OpenID relying party</a>, and one for <a href="http://josephsmarr.com/2008/10/01/using-netflixs-new-api-a-step-by-step-guide/">using Netflix&#8217;s API</a>&#8211;and I&#8217;ve gotten tremendous positive feedback on both, so I think we just need more like that.</li>
<li><strong>Build a &#8220;transparent OAuth Provider&#8221;</strong> that shows the consumer exactly what signature base string, signature key, and signature it was expecting for each request. One of the most vexing aspects of OAuth is that if you make a mistake, you just get a 401 Unauthorized response with little or no debugging help. Clearly in a production system, you can&#8217;t expect the provider to dump out all the secrets they were expecting, but there should be a neutral dummy-API/server where you can test and debug your basic OAuth library or code with full transparency on both sides. In addition, if you&#8217;re accessing your own user-data on a provider&#8217;s site via OAuth, and you&#8217;ve logged in via username and password, there should be a special mode where you can see all the secrets, base strings, etc. that they&#8217;re expecting when you make an OAuth-signed request. (I plan to add this to Plaxo, since right now I achieve it by grepping through our logs and them IMing with the developers who are having problems, and this is, uhh, not scalable.)</li>
<p><strong> 	</strong></p>
<li><strong><strong>Build an OAuth validator for providers and consumers</strong> </strong>that simulates the &#8220;other half&#8221; of the library (i.e. a provider to test consumer-code and a consumer to test provider-code) and that takes the code through a bunch of different scenarios, with detailed feedback at each step. For instance, does the API support GET? POST? Authorization headers? Does it handle empty secrets properly? Does it properly encode special characters? Does it compute the signature properly for known values? Does it properly append parameters to the oauth_callback URL when redirecting? And so on. I think the main reason that libraries and providers so far have all had bugs is that they really didn&#8217;t have a good way to thoroughly test their code. As a rule, if you can&#8217;t test your code, it will have bugs. So if we just encoded the common mistakes we&#8217;ve all seen in the field so far and put those in a validator, future implementations could be confident that they&#8217;ve nailed all the basics before being released in the wild. (And I&#8217;m sure we&#8217;d uncover more bugs in our existing libraries and providers in the process!)</li>
<p><strong> 	</strong></p>
<li><strong><strong>Standardize the terms we use</strong> </strong>both in our tutorials and libraries. The spec itself is pretty consistent, but it&#8217;s already confusing enough to have a &#8220;Consumer Token&#8221;, &#8220;Request Token&#8221;, and &#8220;Access Token&#8221;, each of which consist of a &#8220;Token Key&#8221; and &#8220;Token Secret&#8221;, and it&#8217;s even more confusing when these terms aren&#8217;t used with exact specificity. It&#8217;s too easy to just say &#8220;token&#8221; to mean &#8220;request token&#8221; or &#8220;token&#8221; to mean &#8220;token key&#8221;&#8211;I do it all the time myself, but we really need to keep ourselves sharp when trying to get developers to do the right thing. Worse still, all the existing libraries use different naming conventions for the functions and steps involved, so it&#8217;s hard to write tutorials that work with multiple libraries. We should do a better job of using specific and standard terms in our tutorials and code, and clean up the stuff that&#8217;s already out there.</li>
<li><strong><strong>Consolidate the best libraries and other resources</strong> </strong>so developers have an easier time finding out what the current state-of-the-art is. Questions that should have obvious and easily findable answers include: is there an OAuth library in my language? If so, what&#8217;s the best one to use? How much has it been tested? Are their known bugs? Who should I contact if I run into problems using it? What are the current best tutorials, validators, etc. for me to use? Which companies have OAuth APIs currently? What known issues exist for each of those providers? Where is the forum/mailing-list/etc for each of those APIs? Which e-mail list(s) should I send general OAuth questions to? Should I feel confident that emails sent to those lists will receive prompt replies? Should I expect that bug reports or patches I submit there will quickly find their way to the right place? And so on.</li>
<li><strong><strong>Share more war stories</strong> </strong>of what we&#8217;ve tried, what hasn&#8217;t worked, and what we had to do to make it work. I applauded Dave for suffering his developer pain in public via his blog, and I did the same when working with Netflix&#8217;s API, but if we all did more of that, our collective knowledge of bugs, patterns, tricks, and solutions would be out there for others to find and benefit form. I should do more of that myself, and if you&#8217;ve ever tried to use OAuth, write an OAuth library, or build your own provider, you should too! So to get things started: In Dave&#8217;s case, the ultimate problem turned out to be that he was using his Request Secret instead of his Access Secret when signing API requests. Of course this worked when hitting the OAuth endpoint to get his Access token in the first place, and it&#8217;s a subtle difference (esp. if you don&#8217;t fully grok what all these different tokens are for, which most people don&#8217;t), but it didn&#8217;t work when hitting a protected API, and there&#8217;s no error message on any provider that says &#8220;you used the wrong secret when signing your request&#8221; since the secrets are never transmitted directly. The way I helped him debug it was to literally watch our debugging logs (which spit out all the guts of the OAuth signing process, including Base String, Signature Key, and final Signature), and then I sent him all that info and asked him to print out the same info on his end and compare the two. Once he did that, it was easy to spot and fix the mistake. But I hope you can see how all of the suggestions above would have helped make this process a lot quicker and less painful.</li>
<p><strong> </strong></ul>
<p><strong> </strong>What else can we as a community do to make OAuth easier for developers? Add your thoughts here or in your own blog post. As Dave remarked to me, &#8220;the number of OAuth developers out there is about to skyrocket&#8221; now that Google, Yahoo, MySpace, Twitter, Netflix, TripIt, and more are providing OAuth-protected APIs. So this is definitely the time to put in some extra effort to make sure OAuth can really achieve its full potential!
<div class="social4i" style="height:29px;">
<div class="social4in" style="height:29px;float: left;">
<div class="socialicons s4twitter" style="float:left;margin-right: 10px;"><a href="https://twitter.com/share" data-url="http://josephsmarr.com/2009/02/17/implementing-oauth-is-still-too-hard-but-it-doesnt-have-to-be/" data-counturl="http://josephsmarr.com/2009/02/17/implementing-oauth-is-still-too-hard-but-it-doesnt-have-to-be/" data-text="Implementing OAuth is still too hard&#8230; but it doesn&#8217;t have to be" class="twitter-share-button" data-count="horizontal" data-via="jsmarr"></a></div>
<div class="socialicons s4fblike" style="float:left;margin-right: 10px;">
<div id="fb-root"></div>
<p><fb:like href="http%3A%2F%2Fjosephsmarr.com%2F2009%2F02%2F17%2Fimplementing-oauth-is-still-too-hard-but-it-doesnt-have-to-be%2F" send="false" layout="button_count" width="100" height="21" show_faces="false" font=""></fb:like></div>
<div class="socialicons s4plusone" style="float:left;margin-right: 10px;"><g:plusone size="medium" href="http://josephsmarr.com/2009/02/17/implementing-oauth-is-still-too-hard-but-it-doesnt-have-to-be/" count="true"></g:plusone></div>
</div>
<div style="clear:both"></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://josephsmarr.com/2009/02/17/implementing-oauth-is-still-too-hard-but-it-doesnt-have-to-be/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Using Netflix&#8217;s New API: A step-by-step guide</title>
		<link>http://josephsmarr.com/2008/10/01/using-netflixs-new-api-a-step-by-step-guide/</link>
		<comments>http://josephsmarr.com/2008/10/01/using-netflixs-new-api-a-step-by-step-guide/#comments</comments>
		<pubDate>Thu, 02 Oct 2008 06:43:38 +0000</pubDate>
		<dc:creator>joseph</dc:creator>
				<category><![CDATA[Open Social Web]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://josephsmarr.com/2008/10/01/using-netflixs-new-api-a-step-by-step-guide/</guid>
		<description><![CDATA[As a longtime avid Netflix fan, I was excited to see that they finally released an official API today. As an avid fan of the Open Web, I was even more excited to see that this API gives users full access to their ratings, reviews, and queue, and it does so using a familiar REST [...]]]></description>
			<content:encoded><![CDATA[<p><a title="Netflix announces an API by josephsmarr, on Flickr" href="http://developer.netflix.com/blog/read/Introducing_the_Netflix_API"><img height="222" alt="Netflix announces an API" src="http://farm4.static.flickr.com/3227/2906766868_7d7368f38e_m.jpg" width="240" align="right" /></a>As a longtime avid Netflix fan, I was excited to see that they finally <a href="http://developer.netflix.com/blog/read/Introducing_the_Netflix_API">released an official API</a> today. As an avid fan of the Open Web, I was even more excited to see that this API gives users full access to their ratings, reviews, and queue, and it does so using a familiar REST interface, with output available in XML, JSON, and ATOM. It even uses OAuth to grant access to protected user data, meaning you can pick up an existing <a href="http://oauth.net/code">OAuth library</a> and dive in (well, almost, see below). Netflix has done a great job here, and deserves a lot of kudos!</p>
<p>Naturally, I couldn&#8217;t wait to get my hands on the API and try it out for real. After a bit of tinkering, I&#8217;ve now got it working so it gives me my own list of ratings, reviews, and recently returned movies, including as an ATOM feed that can be embedded as-is into a feed reader or aggregator. It was pretty straightforward, but I noticed a couple of non-standard things and gotchas along the way, so I thought it would be useful to share my findings. Hopefully this will help you get started with Netflix&#8217;s API even faster than I did!</p>
<p>So here&#8217;s how to get started with the Netflix API and end up with an ATOM feed of your recently returned movies:</p>
<ol>
<li><strong>Sign up for mashery</strong> (which hosts Netflix&#8217;s API) at <a href="http://developer.netflix.com/member/register">http://developer.netflix.com/member/register</a> (you have to fill out some basic profile info and respond to an email round-trip)</li>
<li><strong>Register for an application key</strong> at <a href="http://developer.netflix.com/apps/register">http://developer.netflix.com/apps/register</a> (you say a bit about what your app does and it gives you a key and secret). When you submit the registration, it will give you a result like this:
<div style="padding-right: 0.5em; padding-left: 0.5em; background: #f0f0f0; padding-bottom: 0.5em; margin: 0.5em; padding-top: 0.5em; font-family: monospace">Netflix API: k5mds6sfn594x4drvtw96n37   Shared Secret: srKNVRubKX</div>
<p>The first string is your OAuth Consumer Key and the second one is your OAuth Consumer Secret. I&#8217;ve changed the secret above so you don&#8217;t add weird movies to my account, but this gives you an idea of what it looks like. <img src='http://josephsmarr.com/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
<li><strong>Get an OAuth request token.</strong> If you&#8217;re not ready to start writing code, you can use an OAuth test client like <a href="http://term.ie/oauth/example/client.php">http://term.ie/oauth/example/client.php</a>. It&#8217;s not the most user-friendly UI, but it will get the job done. Use HMAC-SHA1 as your signature method, and use <a href="http://api.netflix.com/oauth/request_token">http://api.netflix.com/oauth/request_token</a> as the endpoint. Put your newly issued consumer key and secret in the spaces below, and click the &#8220;request_token&#8221; button. If it works, you&#8217;ll get a page with output like this:
<div style="padding-right: 0.5em; padding-left: 0.5em; background: #f0f0f0; padding-bottom: 0.5em; margin: 0.5em; padding-top: 0.5em; font-family: monospace">oauth_token=bpn8ycnma7hzuwec5dmt8f2j&#038;oauth_token_secret=DArhPYzsUCkz&#038;application_name=JosephSmarrTestApp&#038;login_url=https%3A%2F%2Fapi-user.netflix.com%2Foauth%2Flogin%3Foauth_token%3Dbpn8ycnma7hzuwec5dmt8f2j</div>
<p>Your OAuth library should parse this for you, but if you&#8217;re playing along in the test client, you&#8217;ll have to pull out the OAuth Request Token (in this case, <code>bpn8ycnma7hzuwec5dmt8f2j</code>) and OAuth Request Secret (<code>DArhPYzsUCtt</code>). Note it also tells you the <code>application_name</code> you registered (in this case, <code>JosephSmarrTestApp</code>), which you&#8217;ll need for the next step (this is not a standard part of OAuth, and not sure why they require you to pass it along). They also give you a <code>login_url</code>, which is also non-standard, and doesn&#8217;t actually work, since you need to append additional parameters to it.</li>
<li><strong>Ask the user to authorize your request token.</strong> Here the OAuth test client will fail you because Netflix requires you to append additional query parameters to the login URL, and the test client isn&#8217;t smart about merging query parameters on the endpoint URL with the OAuth parameters it adds. The base login URL is <a href="https://api-user.netflix.com/oauth/login">https://api-user.netflix.com/oauth/login</a> and as usual you have to append your Request Token as oauth_token=bpn8ycnma7hzuwec5dmt8f2j and provide an optional callback URL to redirect to the user to upon success. But it also makes you append your OAuth Consumer Key and application name, so the final URL you need to redirect your user to looks like this:
<div style="padding-right: 0.5em; padding-left: 0.5em; background: #f0f0f0; padding-bottom: 0.5em; margin: 0.5em; padding-top: 0.5em; font-family: monospace"><a href="https://api-user.netflix.com/oauth/login?oauth_token=bpn8ycnma7hzuwec5dmt8f2j&#038;oauth_callback=YOUR_CALLBACK_URL&#038;oauth_consumer_key=k5mds6sfn594x4drvtw96n37&#038;application_name=JosephSmarrTestApp">https://api-user.netflix.com/oauth/login?oauth_token=bpn8ycnma7hzuwec5dmt8f2j&#038;oauth_callback=YOUR_CALLBACK_URL&#038;oauth_consumer_key=k5mds6sfn594x4drvtw96n37&#038;application_name=JosephSmarrTestApp</a></div>
<p>This is not standard behavior, and it will probably cause unnecessary friction for developers, but now you know. BTW if you&#8217;re getting HTTP 400 errors on this step, try curl-ing the URL on the command line, and it will provide a descriptive error message that may not show up in your web browser. For instance, if you leave out the application name, e.g.</p>
<div style="padding-right: 0.5em; padding-left: 0.5em; background: #f0f0f0; padding-bottom: 0.5em; margin: 0.5em; padding-top: 0.5em; font-family: monospace">curl &#8216;https://api-user.netflix.com/oauth/login?oauth_token=bpn8ycnma7hzuwec5dmt8f2j&#038;oauth_callback=YOUR_CALLBACK_URL&#038;oauth_consumer_key=k5mds6sfn594x4drvtw96n37&#8242;</div>
<p>You&#8217;ll get the following XML response (I&#8217;ve replaced the angle brackets with [] because wordpress keeps eating my escaped tags, grr):</p>
<div style="padding-right: 0.5em; padding-left: 0.5em; background: #f0f0f0; padding-bottom: 0.5em; margin: 0.5em; padding-top: 0.5em; font-family: monospace">[status]<br />
  [status_code]400[/status_code]<br />
  [message]application_name is missing[/message]<br />
[/status]</div>
<p>If your login URL is successfully constructed, it will take the user to an authorization page that looks like this:<br />
<a title="Netflix OAuth authorization page by josephsmarr, on Flickr" href="https://api-user.netflix.com/oauth/login?oauth_token=bpn8ycnma7hzuwec5dmt8f2j&#038;oauth_callback=YOUR_CALLBACK_URL&#038;oauth_consumer_key=k5mds6sfn594x4drvtw96n37&#038;application_name=JosephSmarrTestApp"><img style="margin: 0.5em; border: #f0f0f0 0.5em solid" height="360" alt="Netflix OAuth authorization page" src="http://farm4.static.flickr.com/3223/2906840570_eb0b4587f5_o.png" width="461" /></a></p>
<p>If the user approves, they&#8217;ll be redirected back to your oauth_callback URL (if supplied), and your request token has now been authorized.</li>
<li><strong>Exchange your authorized request token for an access token.</strong> You can use the OAuth test client again for this, and it&#8217;s basically just like getting the request token, except the endpoint is <a href="http://api.netflix.com/oauth/access_token">http://api.netflix.com/oauth/access_token</a> and you need to fill out both your consumer token and secret as well as your request token and secret. Then click the access_token button, and you should get a page with output like this:
<div style="padding-right: 0.5em; padding-left: 0.5em; background: #f0f0f0; padding-bottom: 0.5em; margin: 0.5em; padding-top: 0.5em; font-family: monospace">oauth_token=T1lVQLSlIW38NDgeumjnyypbxc6yHD0xkaD21d8DpLVaIs3d2T1Aq_yeOor9PCIW2Bz5ksIPr7aXBKvTTg599m9Q&#8211;&#038;user_id=T1G.NK54IqxGkXi3RbkKgudF3ZFkmopPt3lR.dlOLC898-&#038;oauth_token_secret=AKeGYam8NJ4X</div>
<p>(Once again I&#8217;ve altered my secret to protect the innocent.) In addition to providing an OAuth Access Token and OAuth Access Secret (via the oauth_token and oauth_token_secret parameters, respectively), you are also given the user_id for the authorized user, which you need to use when constructing the full URL for REST API calls. This is non-standard for OAuth, and you may need to modify your OAuth library to return this additional parameter, but that&#8217;s where you get it. (It would be nice if you could use an implicit userID in API URLs like @me, and it could be interpreted as &#8220;the user that granted this access token&#8221;, so you could skip this step of having to extract and use an explicit userID; that&#8217;s how Portable Contacts and OpenSocial get around this problem. Feature request, anyone?)</li>
<li><strong>Use your access token to fetch the user&#8217;s list of protected feeds.</strong> Having now successfully gone through the OAuth dance, you&#8217;re now ready to make your first protected API call! You can browse the list of available API calls at <a href="http://developer.netflix.com/docs/REST_API_Reference">http://developer.netflix.com/docs/REST_API_Reference</a> and in each case, the URL starts out as <a href="http://api.netflix.com/">http://api.netflix.com/</a> and you append the path, substituting the user_id value you got back with your access token wherever the path calls for <em>userID</em>. So for instance, to get the list of protected ATOM feeds for the user, the REST URL is <a href="http://api.netflix.com/users/userID/feeds">http://api.netflix.com/users/<em>userID</em>/feeds</a>, or in this case <a href="http://api.netflix.com/users/T1G.NK54IqxGkXi3RbkKgudF3ZFkmopPt3lR.dlOLC898-/feeds">http://api.netflix.com/users/T1G.NK54IqxGkXi3RbkKgudF3ZFkmopPt3lR.dlOLC898-/feeds</a>.
<p>Here&#8217;s where the OAuth test client is a bit confusing: you need put that feeds URL as the endpoint, fill out the consumer key and secret as normal, and fill out your *access* token and secret under the &#8220;request token / secret&#8221; fields, then click the &#8220;access_token&#8221; button to submit the OAuth-signed API request. If it works, you&#8217;ll get an XML response with a bunch of links to different protected feeds available for this user. Here&#8217;s an example of the response, showing just a couple of the returned links, and again with angle brackets replaced with square brackets to appease my lame wordpress editor:</p>
<div style="padding-right: 0.5em; padding-left: 0.5em; background: #f0f0f0; padding-bottom: 0.5em; margin: 0.5em; padding-top: 0.5em; font-family: monospace">[resource]<br />
  [link href="<a href="http://api.netflix.com/users/T1G.NK54IqxGkXi3RbkKgudF3ZFkmopPt3lR.dlOLC898-/queues/instant?feed_token=T1v23xnWpcYnhhkIsQ_iyASermOnPjgFKP77FdaXGkWEqUvwrPAjTeVHlgLpMlx2FF&#038;oauth_consumer_key=k5mds6sfn594x4drvtw96n37&#038;output=atom">http://api.netflix.com/users/T1G.NK54IqxGkXi3RbkKgudF3ZFkmopPt3lR.dlOLC898-/queues/instant?feed_token=T1v23xnWpcYnhhkIsQ_iyASermOnPjgFKP77FdaXGkWEqUvwrPAjTeVHlgLpMlx2FF&#038;oauth_consumer_key=k5mds6sfn594x4drvtw96n37&#038;output=atom</a>" rel="<a href="http://schemas.netflix.com/feed.queues.instant">http://schemas.netflix.com/feed.queues.instant</a>" title="Instant Queue"][/link]<br />
  [link href="<a href="http://api.netflix.com/users/T1G.NK54IqxGkXi3RbkKgudF3ZFkmopPt3lR.dlOLC898-/rental_history/returned?feed_token=T1ksEAR97Ki14sIyQX2pfnGH0Llom4eaIDMwNWlUOmRZ0duD2YDbp_5PPUKBcedH51XSxPTnUOI5rCLz9feBXx9A--&#038;oauth_consumer_key=k5mds6sfn594x4drvtw96n37&#038;output=atom">http://api.netflix.com/users/T1G.NK54IqxGkXi3RbkKgudF3ZFkmopPt3lR.dlOLC898-/rental_history/returned?feed_token=T1ksEAR97Ki14sIyQX2pfnGH0Llom4eaIDMwNWlUOmRZ0duD2YDbp_5PPUKBcedH51XSxPTnUOI5rCLz9feBXx9A--&#038;oauth_consumer_key=k5mds6sfn594x4drvtw96n37&#038;output=atom</a>" rel="<a href="http://schemas.netflix.com/feed.rental_history.returned">http://schemas.netflix.com/feed.rental_history.returned</a>" title="Titles Returned Recently"][/link]<br />
[/resource]</div>
<p>Each link contains an href attribute pointing to the actual feed URL, as well as a rel attribute describing the type of data available for that link, and a human-readable title attribute. In our case, we want the &#8220;Titles Returned Recently&#8221; feed, which is available at <a href="http://api.netflix.com/users/T1G.NK54IqxGkXi3RbkKgudF3ZFkmopPt3lR.dlOLC898-/rental_history/returned?feed_token=T1ksEAR97Ki14sIyQX2pfnGH0Llom4eaIDMwNWlUOmRZ0duD2YDbp_5PPUKBcedH51XSxPTnUOI5rCLz9feBXx9A--&#038;oauth_consumer_key=k5mds6sfn594x4drvtw96n37&#038;output=atom">http://api.netflix.com/users/T1G.NK54IqxGkXi3RbkKgudF3ZFkmopPt3lR.dlOLC898-/rental_history/returned?feed_token=T1ksEAR97Ki14sIyQX2pfnGH0Llom4eaIDMwNWlUOmRZ0duD2YDbp_5PPUKBcedH51XSxPTnUOI5rCLz9feBXx9A&#8211;&#038;oauth_consumer_key=k5mds6sfn594x4drvtw96n37&#038;output=atom</a> (note the XML escapes &#038;s in URLs as XML entities, so you have to un-escape them to get the actual URL). As you can see, this feed URL looks like a normal API request, including my userID on the path, but with an extra feed_token parameter, which is different for each available user feed. This way, the ATOM feed can be fetched without having to do any OAuth signing, so you can drop it in your feed reader or aggregator of choice and it should just work. And giving access to one feed won&#8217;t let anyone access your other feeds, since they&#8217;re each protected with their own feed_token values.</li>
<li><strong>Fetch the feed of recently returned movies.</strong> Now you can just fetch the feed URL you found in the previous step (in my case, <a href="http://api.netflix.com/users/T1G.NK54IqxGkXi3RbkKgudF3ZFkmopPt3lR.dlOLC898-/rental_history/returned?feed_token=T1ksEAR97Ki14sIyQX2pfnGH0Llom4eaIDMwNWlUOmRZ0duD2YDbp_5PPUKBcedH51XSxPTnUOI5rCLz9feBXx9A--&#038;oauth_consumer_key=k5mds6sfn594x4drvtw96n37&#038;output=atom">http://api.netflix.com/users/T1G.NK54IqxGkXi3RbkKgudF3ZFkmopPt3lR.dlOLC898-/rental_history/returned?feed_token=T1ksEAR97Ki14sIyQX2pfnGH0Llom4eaIDMwNWlUOmRZ0duD2YDbp_5PPUKBcedH51XSxPTnUOI5rCLz9feBXx9A&#8211;&#038;oauth_consumer_key=k5mds6sfn594x4drvtw96n37&#038;output=atom</a>), and you&#8217;ll get nicely formatted &#8220;blog posts&#8221; back for each movie the user recently returned. Here&#8217;s a sample of how the formatted ATOM entries look:<br />
<a title="Netflix rental returns as a feed by josephsmarr, on Flickr" href="http://api.netflix.com/users/T1G.NK54IqxGkXi3RbkKgudF3ZFkmopPt3lR.dlOLC898-/rental_history/returned?feed_token=T1ksEAR97Ki14sIyQX2pfnGH0Llom4eaIDMwNWlUOmRZ0duD2YDbp_5PPUKBcedH51XSxPTnUOI5rCLz9feBXx9A--&#038;oauth_consumer_key=k5mds6sfn594x4drvtw96n37&#038;output=atom"><img style="margin: 0.5em; border: #f0f0f0 0.5em solid" height="287" alt="Netflix rental returns as a feed" src="http://farm4.static.flickr.com/3218/2906039547_161f99c167_o.png" width="416" /></a><br />
Of course, if you want to format the results differently, you can make a REST API call for the same data, e.g. <a href="http://api.netflix.com/users/userID/rental_history/returned">http://api.netflix.com/users/<em>userID</em>/rental_history/returned</a> OAuth-sign it like you did in step 6, and you&#8217;ll get all the meta-data for each movie returned as XML, including various sizes of movie poster image.</li>
<li><strong>Profit! </strong>Now you&#8217;ve got a way to let your users provide access to their netflix data, which you can use in a variety of ways to enhance your site. If this is the first time you&#8217;ve used OAuth, it might have seemed a little complex, but the good news is it&#8217;s the same process for all other OAuth-protected APIs you may want to use in the future.</li>
</ol>
<p>I hope you found this helpful. If anything is confusing, or if I made any mistakes in my write-up, please leave a comment so I can make it better. Otherwise, let me know when you&#8217;ve got your Netflix integration up and running!
<div class="social4i" style="height:29px;">
<div class="social4in" style="height:29px;float: left;">
<div class="socialicons s4twitter" style="float:left;margin-right: 10px;"><a href="https://twitter.com/share" data-url="http://josephsmarr.com/2008/10/01/using-netflixs-new-api-a-step-by-step-guide/" data-counturl="http://josephsmarr.com/2008/10/01/using-netflixs-new-api-a-step-by-step-guide/" data-text="Using Netflix&#8217;s New API: A step-by-step guide" class="twitter-share-button" data-count="horizontal" data-via="jsmarr"></a></div>
<div class="socialicons s4fblike" style="float:left;margin-right: 10px;">
<div id="fb-root"></div>
<p><fb:like href="http%3A%2F%2Fjosephsmarr.com%2F2008%2F10%2F01%2Fusing-netflixs-new-api-a-step-by-step-guide%2F" send="false" layout="button_count" width="100" height="21" show_faces="false" font=""></fb:like></div>
<div class="socialicons s4plusone" style="float:left;margin-right: 10px;"><g:plusone size="medium" href="http://josephsmarr.com/2008/10/01/using-netflixs-new-api-a-step-by-step-guide/" count="true"></g:plusone></div>
</div>
<div style="clear:both"></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://josephsmarr.com/2008/10/01/using-netflixs-new-api-a-step-by-step-guide/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
		<item>
		<title>Performance Challenges for the Open Web (Stanford CS193H)</title>
		<link>http://josephsmarr.com/2008/09/30/performance-challenges-for-the-open-web-stanford-cs193h/</link>
		<comments>http://josephsmarr.com/2008/09/30/performance-challenges-for-the-open-web-stanford-cs193h/#comments</comments>
		<pubDate>Tue, 30 Sep 2008 18:37:44 +0000</pubDate>
		<dc:creator>joseph</dc:creator>
				<category><![CDATA[Open Social Web]]></category>
		<category><![CDATA[Papers and Talks]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://josephsmarr.com/2008/09/30/performance-challenges-for-the-open-web-stanford-cs193h/</guid>
		<description><![CDATA[Performance Challenges for the Open Web Stanford CS193H: High Performance Web Sites Stanford, CA September 29, 2008 Download PPT (6.8 MB) Web site performance guru Steve Souders is teaching a class at Stanford this fall on High Performance Web Sites (CS193H). He invited me to give a guest lecture to his class on the new [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Performance Challenges for the Open Web</strong><a href="http://cs193h.stevesouders.com/"><strong><br />
</strong></a><a href="http://cs193h.stevesouders.com/">Stanford CS193H: High Performance Web Sites</a><br />
Stanford, CA<br />
September 29, 2008</p>
<p><a href="http://josephsmarr.com/papers/Smarr-CS193H.ppt">Download PPT</a> (6.8 MB)</p>
<p><a title="Open Web brings new performance challenges by josephsmarr, on Flickr" href="http://www.flickr.com/photos/jsmarr/2902207996/in/set-72157607607273291/"><img height="180" align="right" width="240" alt="Open Web brings new performance challenges" src="http://farm4.static.flickr.com/3127/2902207996_61acf22996_m.jpg" /></a>Web site performance guru <a href="http://www.stevesouders.com">Steve Souders</a> is teaching a class at Stanford this fall on High Performance Web Sites (<a href="http://cs193h.stevesouders.com/">CS193H</a>). He invited me to give a guest lecture to his class on the new performance challenges emerging from our work to open up the social web. As a recent Stanford alum (<a href="http://symsys.stanford.edu/">SSP</a> &#8217;02, co-term &#8217;03), it was a thrill to get to teach a class at my alma mater, esp. in the basement of the Gates bldg, where I&#8217;ve taken many classes myself.</p>
<p>I originally met Steve at <a href="http://josephsmarr.com/2007/07/25/high-performance-javascript-oscon-2007/">OSCON 07</a> when I was working on high-performance JavaScript, and we were giving back-to-back talks. We immediately hit it off and have remained in good touch since. Over the last year or so, however, my focus has shifted to <a href="http://josephsmarr.com/category/open-social-web/">opening up the social web</a>. So when Steve asked me to speak at his class, my first reaction was &#8220;I&#8217;m not sure I could tell your students anything new that isn&#8217;t already in your book&#8221;.</p>
<p>But upon reflection, I realized that a lot of the key challenges in creating a truly social web are directly related to performance, and the set of performance challenges in this space are quite different than in optimizing a single web site. In essence, the challenge is getting multiple sites to work together and share content in a way that&#8217;s open and flexible but also tightly integrated and high-performance. Thus <a href="http://josephsmarr.com/papers/Smarr-CS193H.ppt">my new talk</a> was born.</p>
<p><a title="Lots of open building blocks by josephsmarr, on Flickr" href="http://www.flickr.com/photos/jsmarr/2901366645/in/set-72157607607273291/"><img height="180" align="right" width="240" alt="Lots of open building blocks" src="http://farm4.static.flickr.com/3230/2901366645_6865e4762b_m.jpg" /></a>I provided the students with an overview of the emerging social web ecosystem, and some of the key open building blocks making it possible (OpenID, OAuth, OpenSocial, XRDS-Simple, microformats, etc.). I then gave some concrete examples of how these building blocks can play together, and that led naturally into a discussion of the performance challenges involved.</p>
<p>I broke the challenges into four primary categories:</p>
<ul>
<li><strong>minimizing round trips</strong> (the challenge is combining steps to optimize vs. keeping the pieces flexible and simple),</li>
<li><strong>caching </strong>(storing copies of user data for efficiency vs. always having a fresh copy),</li>
<li><strong>pull vs. push</strong> (the difficulty of scaling mass-polling and the opportunities presented by XMPP and Gnip to decrease both latency and load), and</li>
<li><strong>integrating third-party content</strong> (proxying vs. client-side fetching, iframes vs. inline integration, etc.).</li>
</ul>
<p>In each of these cases, there are fundamental trade-offs to make, so there&#8217;s no &#8220;easy, right answer&#8221;. But by understanding the issues involved, you can make trade-offs that are tailored to the situation at hand. Some of the students in that class will probably be writing the next generation of social apps, so I&#8217;m glad they can start thinking about these important issues today.
<div class="social4i" style="height:29px;">
<div class="social4in" style="height:29px;float: left;">
<div class="socialicons s4twitter" style="float:left;margin-right: 10px;"><a href="https://twitter.com/share" data-url="http://josephsmarr.com/2008/09/30/performance-challenges-for-the-open-web-stanford-cs193h/" data-counturl="http://josephsmarr.com/2008/09/30/performance-challenges-for-the-open-web-stanford-cs193h/" data-text="Performance Challenges for the Open Web (Stanford CS193H)" class="twitter-share-button" data-count="horizontal" data-via="jsmarr"></a></div>
<div class="socialicons s4fblike" style="float:left;margin-right: 10px;">
<div id="fb-root"></div>
<p><fb:like href="http%3A%2F%2Fjosephsmarr.com%2F2008%2F09%2F30%2Fperformance-challenges-for-the-open-web-stanford-cs193h%2F" send="false" layout="button_count" width="100" height="21" show_faces="false" font=""></fb:like></div>
<div class="socialicons s4plusone" style="float:left;margin-right: 10px;"><g:plusone size="medium" href="http://josephsmarr.com/2008/09/30/performance-challenges-for-the-open-web-stanford-cs193h/" count="true"></g:plusone></div>
</div>
<div style="clear:both"></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://josephsmarr.com/2008/09/30/performance-challenges-for-the-open-web-stanford-cs193h/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Future of Social Networks (Future of Web Apps Miami)</title>
		<link>http://josephsmarr.com/2008/03/14/the-future-of-social-networks-future-of-web-apps-miami/</link>
		<comments>http://josephsmarr.com/2008/03/14/the-future-of-social-networks-future-of-web-apps-miami/#comments</comments>
		<pubDate>Fri, 14 Mar 2008 15:47:43 +0000</pubDate>
		<dc:creator>joseph</dc:creator>
				<category><![CDATA[Open Social Web]]></category>
		<category><![CDATA[Papers and Talks]]></category>
		<category><![CDATA[Plaxo]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://josephsmarr.com/2008/03/14/the-future-of-social-networks-future-of-web-apps-miami/</guid>
		<description><![CDATA[The Future of Social Networks Future of Web Apps Miami (with Tantek Çelik and Brian Oberkirch) Miami, FL February 29, 2008 View Slides (slideshare) Download MP3 Audio (37.3 MB) In addition to the half-day workshop I presented at FOWA Miami, I also gave a talk as part of the main event with Tantek and Brian Orberkirch (who also has [...]]]></description>
			<content:encoded><![CDATA[<p><strong>The Future of Social Networks<br />
</strong><a href="http://futureofwebapps.com/2008/miami/schedule.php">Future of Web Apps Miami</a> (with Tantek Çelik and Brian Oberkirch)<br />
Miami, FL<br />
February 29, 2008</p>
<p><a href="http://www.slideshare.net/brianoberkirch/fowa-miami-future-of-social-networks">View Slides</a> (slideshare)<br />
<a href="http://cdn4.libsyn.com/carsonsystems/Brian_Tantek__Joseph.mp3">Download MP3 Audio</a> (37.3 MB)</p>
<p><a href="http://www.flickr.com/photos/knmurphy/2303125376/"><img height="159" src="http://farm4.static.flickr.com/3150/2303125376_b870ae7fa2_m_d.jpg" width="240" align="right" /></a>In addition to the <a href="http://josephsmarr.com/2008/03/02/implementing-open-social-web-support-on-your-site-future-of-web-apps-miami/">half-day workshop</a> I presented at FOWA Miami, I also gave a talk as part of the main event with <a href="http://tantek.com/">Tantek</a> and <a href="http://brianoberkirch.com/">Brian Orberkirch</a> (who also has a <a href="http://www.brianoberkirch.com/2008/03/07/fowa-miami-celik-smarr-oberkirch-on-more-social-social-networks/">great write-up</a> of our talk) on <a href="http://www.slideshare.net/brianoberkirch/fowa-miami-future-of-social-networks">The Future of Social Networks</a>. I summarized my remarks in <a href="http://josephsmarr.com/2008/03/02/implementing-open-social-web-support-on-your-site-future-of-web-apps-miami/">my previous FOWA post</a>, but I wanted to add a separate post for this talk so I could link to the slides and audio (and video should be available soon as well). FOWA was a great event, and I&#8217;m eager for the next one!
<div class="social4i" style="height:29px;">
<div class="social4in" style="height:29px;float: left;">
<div class="socialicons s4twitter" style="float:left;margin-right: 10px;"><a href="https://twitter.com/share" data-url="http://josephsmarr.com/2008/03/14/the-future-of-social-networks-future-of-web-apps-miami/" data-counturl="http://josephsmarr.com/2008/03/14/the-future-of-social-networks-future-of-web-apps-miami/" data-text="The Future of Social Networks (Future of Web Apps Miami)" class="twitter-share-button" data-count="horizontal" data-via="jsmarr"></a></div>
<div class="socialicons s4fblike" style="float:left;margin-right: 10px;">
<div id="fb-root"></div>
<p><fb:like href="http%3A%2F%2Fjosephsmarr.com%2F2008%2F03%2F14%2Fthe-future-of-social-networks-future-of-web-apps-miami%2F" send="false" layout="button_count" width="100" height="21" show_faces="false" font=""></fb:like></div>
<div class="socialicons s4plusone" style="float:left;margin-right: 10px;"><g:plusone size="medium" href="http://josephsmarr.com/2008/03/14/the-future-of-social-networks-future-of-web-apps-miami/" count="true"></g:plusone></div>
</div>
<div style="clear:both"></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://josephsmarr.com/2008/03/14/the-future-of-social-networks-future-of-web-apps-miami/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://cdn4.libsyn.com/carsonsystems/Brian_Tantek__Joseph.mp3" length="39196774" type="audio/mpeg" />
		</item>
		<item>
		<title>Implementing Open Social Web support on your site (Future of Web Apps Miami)</title>
		<link>http://josephsmarr.com/2008/03/02/implementing-open-social-web-support-on-your-site-future-of-web-apps-miami/</link>
		<comments>http://josephsmarr.com/2008/03/02/implementing-open-social-web-support-on-your-site-future-of-web-apps-miami/#comments</comments>
		<pubDate>Sun, 02 Mar 2008 09:48:53 +0000</pubDate>
		<dc:creator>jsmarr</dc:creator>
				<category><![CDATA[Open Social Web]]></category>
		<category><![CDATA[Papers and Talks]]></category>
		<category><![CDATA[Plaxo]]></category>
		<category><![CDATA[Web development]]></category>

		<guid isPermaLink="false">http://josephsmarr.com/2008/03/02/implementing-open-social-web-support-on-your-site-future-of-web-apps-miami/</guid>
		<description><![CDATA[Implementing Open Social Web support on your site Future of Web Apps Miami (workshop) Miami, FL February 28, 2008 Download PPT (3.8 MB) I was invited to give a workshop and be on a panel at the Future of Web Apps in Miami. I attended the first FOWA in SF in 2006, and I really enjoyed [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Implementing Open Social Web support on your site<br />
</strong><a href="http://futureofwebapps.com/2008/miami/workshops.php#jumper05">Future of Web Apps Miami</a> (workshop)<br />
Miami, FL<br />
February 28, 2008</p>
<p><a href="http://josephsmarr.com/papers/Smarr-FOWA-Miami-Workshop-Open-Social-Web.ppt">Download PPT</a> (3.8 MB)</p>
<p><a href="http://flickr.com/photos/jsmarr/sets/72157604007587248/"><img height="180" src="http://farm3.static.flickr.com/2227/2299586035_f166c120a6_m.jpg" width="240" align="right" /></a>I was invited to give a workshop and be on a panel at the Future of Web Apps in Miami. I attended the first FOWA in SF in 2006, and I really enjoyed it, so it was fun to get to be on stage this time. I&#8217;d never done a long workshop before, but I love talking about Open Social Web technologies, so I basically went through all of the various building blocks (OpenID, OAuth, microformats, OpenSocial, Social Graph API, friends-list portability, URLs as identifiers, etc.) and wrapped it in some high-level context about the emergence of a Social Web. The audience was very lively and engaged, and they asked a ton of great questions. So I was very happy with how it all worked out. These are <a href="http://josephsmarr.com/papers/Smarr-FOWA-Miami-Workshop-Open-Social-Web.ppt">the slides from my workshop</a>; they&#8217;re a bit light since I was mainly using them as a reference to talk over. But hopefully they provide some useful jumping-off points to learn more.</p>
<p><a href="http://flickr.com/photos/scrapblogmiami/2300948744/in/set-72157604019400057"><img height="240" src="http://farm4.static.flickr.com/3227/2300948744_1c0ea949cd_m.jpg" width="160" align="right" /></a>I also gave a presentation on the main stage about the future of social networks with Tantek and Brian Oberkirch. Brian made the slides, which hopefully he&#8217;ll post too. My piece of the talk was called &#8220;Open for business&#8221; and it was about how being open can be good for your company, because it lowers friction to signing up and sharing, and it makes you a more relevant part of the online ecosystem. I showed demos of how you can sign up for Plaxo with an OpenID and pre-fill your registration info, discover and auto-suggest sites to add to Pulse using Google&#8217;s Social Graph API, and express yourself in new ways using OpenSocial gadgets. I think it helped the audience see that these open technologies aren&#8217;t just a cool idea, you can actually implement them today, as we have, and they work well enough to benefit mainstream users.</p>
<p><a title="DSC02315 by josephsmarr, on Flickr" href="http://www.flickr.com/photos/jsmarr/tags/powncebrunch/"><img height="180" src="http://farm3.static.flickr.com/2030/2303555429_3884365ff7_m.jpg" width="240" align="right" /></a>After the conference, there was a beach party at Nikki beach, and on Saturday, a bunch of us went with Leah Culver and Kevin Rose to attend the first <a href="http://blog.pownce.com/2008/02/28/upcoming-pownce-brunch-meetups/">Pownce Brunch</a> to meet fellow users. We even managed to sneak in a little shopping and some beach volleyball. But of course we were talking about code and startups the entire time, since we all tend to lack that so-called &#8220;work-life balance&#8221;. <img src='http://josephsmarr.com/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Another highlight for me was meeting Gary Vaynerchuk, the star of <a href="http://tv.winelibrary.com/">Wine Library TV</a>. I&#8217;m surprised I&#8217;d never heard of him (since I&#8217;m into both wine and disruptive technologies), and he was super cool and friendly and is clearly having a major impact. He taped an episode of his show live at FOWA, and he and Kevin and I even came up with an idea for a side project that we may try to spin up sometime&#8230;</p>
<p>I returned home late Saturday night (thanks to Pete for picking me up!) and tomorrow I&#8217;m back on the road: GSP, MIX, and SXSW. Gotta keep <a href="http://josephsmarr.com/2008/02/27/open-social-web-coming-soon-to-a-conference-near-you/">spreading the good word</a>!
<div class="social4i" style="height:29px;">
<div class="social4in" style="height:29px;float: left;">
<div class="socialicons s4twitter" style="float:left;margin-right: 10px;"><a href="https://twitter.com/share" data-url="http://josephsmarr.com/2008/03/02/implementing-open-social-web-support-on-your-site-future-of-web-apps-miami/" data-counturl="http://josephsmarr.com/2008/03/02/implementing-open-social-web-support-on-your-site-future-of-web-apps-miami/" data-text="Implementing Open Social Web support on your site (Future of Web Apps Miami)" class="twitter-share-button" data-count="horizontal" data-via="jsmarr"></a></div>
<div class="socialicons s4fblike" style="float:left;margin-right: 10px;">
<div id="fb-root"></div>
<p><fb:like href="http%3A%2F%2Fjosephsmarr.com%2F2008%2F03%2F02%2Fimplementing-open-social-web-support-on-your-site-future-of-web-apps-miami%2F" send="false" layout="button_count" width="100" height="21" show_faces="false" font=""></fb:like></div>
<div class="socialicons s4plusone" style="float:left;margin-right: 10px;"><g:plusone size="medium" href="http://josephsmarr.com/2008/03/02/implementing-open-social-web-support-on-your-site-future-of-web-apps-miami/" count="true"></g:plusone></div>
</div>
<div style="clear:both"></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://josephsmarr.com/2008/03/02/implementing-open-social-web-support-on-your-site-future-of-web-apps-miami/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

