<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Alex Kahn Blog</title>
 <link href="http://akahn.net/atom.xml" rel="self" />
 <link href="http://akahn.net/"/>
 <updated>2010-02-23T09:29:21-05:00</updated>
 <id>http://akahn.net</id>
 <author>
   <name>Alex Kahn</name>
   <email>alexanderkahn@gmail.com</email>
 </author>

 
 <entry>
   <title>A Sinatra App Wrapping Flickr, Plus HTTP Caching and Heroku</title>
   <link rel="alternate" type="text/html" href="http://akahn.net//2010/02/22/sinatra-app-wrapping-flickr-http-caching-heroku.html" />
   <updated>2010-02-22T00:00:00-05:00</updated>
   <id>http://akahn.net/2010/02/22/sinatra-app-wrapping-flickr-http-caching-heroku</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://recent-work.estherswhite.net&quot;&gt;&lt;img src=&quot;/images/recent-work.jpg&quot; title=&quot;Screenshot of Esther S White: Recent Work&quot; alt=&quot;Screenshot of Esther S White: Recent Work&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the last several months, &lt;a href=&quot;http://www.estherswhite.net&quot;&gt;Esther&lt;/a&gt; has produced a large number of monotype prints at a local printmaking studio. She&amp;#8217;s been sharing her work online by scanning it and posting it to Flickr. Recently she experimented with using Tumblr to create a stylish gallery of this work. But this process &amp;mdash; scanning, adding metadata, uploading to Flickr, followed by posting each piece to Tumblr &amp;mdash; proved to be laborious. So we sought to streamline this workflow, hoping to eliminate a step or two.&lt;/p&gt;
&lt;p&gt;Titles, descriptions, tags and sets are all easy to manage on Flickr. What if there was a way to take advantage of Flickr&amp;#8217;s great management interface, taking images and metadata and putting them on an external site? I took on this problem with a &lt;a href=&quot;http://github.com/akahn/recent-work.estherswhite.net&quot;&gt;Sinatra application that wraps the Flickr &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; in a warm embrace&lt;/a&gt;. The app makes an &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; request to Flickr asking for all the images from Esther&amp;#8217;s &lt;a href=&quot;http://www.flickr.com/photos/estherswhite/sets/72157622782141504/&quot;&gt;printmaking photoset&lt;/a&gt; and renders them as thumbnails, each image linking to a page for that image. On the individual image page, the app requests information on an image &amp;ndash; title, description, and the next and previous image &amp;ndash; and displays this information along with a larger image of the piece. Now, Flickr itself is the &lt;span class=&quot;caps&quot;&gt;CMS&lt;/span&gt; and the gallery is just a pretty shell for information already stored on Flickr. No more managing metadata in multiple places. &lt;a href=&quot;http://recent-work.estherswhite.net&quot;&gt;Have a look at the site.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What about performance? Isn&amp;#8217;t it slow to make an &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; request to Flickr for every visit to the site? This is a definite concern: making an &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; call to Flickr and then responding takes the application about 500ms &amp;ndash; respectable but not exactly speedy. But the content of the site is basically static. Once an image is uploaded and described on Flickr, it is unlikely to change. This means I can cache the entire page with a gateway cache&lt;sup&gt;1&lt;/sup&gt;. To do this, I set &lt;code&gt;Cache-Control&lt;/code&gt; headers that say that my pages are allowed to be cached for long time, and the cache, Varnish, serves up a static representation of the page that the app produced. Once a page has been requested once, subsequent requests for that page are lightning-fast &amp;ndash; under 100ms. After six hours, the cached representation of the homepage is considered stale, and a new one will be generated. After two days, the cached representation of an individual page is considered stale. This way, updates to the photoset or changes to images do eventually get served to visitors.&lt;/p&gt;
&lt;p&gt;I should note that I&amp;#8217;m hosting this site on Heroku. It&amp;#8217;s been said elsewhere and should perhaps be obvious by now, but I&amp;#8217;ll say it again: Heroku is awesome. &lt;a href=&quot;http://docs.heroku.com/http-caching&quot;&gt;Their use of Varnish&lt;/a&gt; made it so easy to make this gallery app fast. Deploying code with just a &lt;code&gt;git push&lt;/code&gt; is seriously great. I recommend hosting an app on Heroku if you haven&amp;#8217;t before. It&amp;#8217;s easy and, for a simple app like this one, is free.&lt;/p&gt;
&lt;p class=&quot;notes&quot;&gt;1: For more on &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; caching, see Ryan Tomayko&amp;#8217;s excellent article &lt;a href=&quot;http://tomayko.com/writings/things-caches-do&quot;&gt;Things Caches Do&lt;/a&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>FakeWeb and Regular Expressions</title>
   <link rel="alternate" type="text/html" href="http://akahn.net//2009/12/16/fakeweb-regular-expressions.html" />
   <updated>2009-12-16T00:00:00-05:00</updated>
   <id>http://akahn.net/2009/12/16/fakeweb-regular-expressions</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://fakeweb.rubyforge.org/&quot;&gt;FakeWeb&lt;/a&gt; is a great way to speed up your tests and remove dependencies on external web services. Using FakeWeb is simple: specify a &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; for FakeWeb to respond to, and give it the response you expect from the request. For example:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;FakeWeb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.google.com&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Stubbed Google!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;HTTParty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.google.com&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;Stubbed Google!&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now FakeWeb will prevent your code from making an actual &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; request and instead it will return the response you specified. But what if your application makes requests to URLs with query parameters? It would be tedious to register each &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; with FakeWeb:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;FakeWeb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.google.com/search?q=fakeweb&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Stubbed Google!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;FakeWeb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.google.com/search?q=excited+kitten&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Stubbed Google!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;FakeWeb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.google.com/search?q=ponies&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Stubbed Google!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Thankfully, FakeWeb has a (slightly underdocumented) solution for this. Instead of passing a string to &lt;code&gt;FakeWeb.register_uri&lt;/code&gt;, pass it a regular expression (using Ruby&amp;#8217;s &lt;code&gt;%r||&lt;/code&gt; syntax to avoid having to escape forward slashes):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;FakeWeb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;%r|http://www.google.com/search\?q=|&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;A bunch of results&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;HTTParty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.google.com/search?q=tunisia&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;A bunch of results&amp;quot;&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;HTTParty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.google.com/search?q=vegan+latkes&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;A bunch of results&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;By registering a regular expression, FakeWeb will respond to any &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; request whose &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; matches the pattern you&amp;#8217;ve supplied. Your test suite can make requests with all different query parameters without having to register each individual &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;. This feature adds a lot of flexibility to FakeWeb and makes it feasible to stub out your application&amp;#8217;s &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; requests, even when complex, changing query parameters are involved.&lt;/p&gt;
&lt;p&gt;For a general overview of FakeWeb, as well a some far-less-contrived examples of its use, check out Josh Nichols&amp;#8217; post, &lt;a href=&quot;http://technicalpickles.com/posts/stop-net-http-dead-in-its-tracks-with-fakeweb/&quot;&gt;Stop Net::&lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; dead in its tracks&lt;/a&gt;. Also check out &lt;a href=&quot;http://github.com/chrisk/fakeweb&quot;&gt;FakeWeb on GitHub&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Pretty Feed Items with Facebook Connect</title>
   <link rel="alternate" type="text/html" href="http://akahn.net//2009/11/06/pretty-feed-items-with-facebook-connect.html" />
   <updated>2009-11-06T00:00:00-05:00</updated>
   <id>http://akahn.net/2009/11/06/pretty-feed-items-with-facebook-connect</id>
   <content type="html">&lt;p&gt;At Free Press, when a user signs a petition or shows support for our issues on one of our sites, we want them to spread the word. We want to make it easy for users to share the story they told, or the petition they signed, and to encourage others to do the same. We usually do this with links to &lt;a href=&quot;http://www.facebook.com/sharer.php?u=http://www.akahn.net/2009/11/06/pretty-feed-items-with-facebook-connect.html&quot;&gt;Facebook&amp;#8217;s &lt;code&gt;sharer.php&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/home?status=http://www.akahn.net/2009/11/06/pretty-feed-items-with-facebook-connect.html%20--%20Not%20too%20shabby&quot;&gt;Twitter&amp;#8217;s status parameter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But &lt;code&gt;sharer.php&lt;/code&gt; left us frustrated with its awkward interface and lack of branding. What about the pretty updates that Facebook applications produce? We wanted a feed item that looked branded, looked good, and compelled a user&amp;#8217;s friends to also take action. This is where Facebook Connect comes in.&lt;/p&gt;
&lt;p&gt;Using Facebook Connect for this task turned out to be simple. Surprisingly simple. Here&amp;#8217;s the routine:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.facebook.com/developers/&quot;&gt;Create a Facebook application&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://wiki.developers.facebook.com/index.php/Cross_Domain_Communication_Channel&quot;&gt;Create a file to allow cross-domain JavaScript communication&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://wiki.developers.facebook.com/index.php/FeatureLoader.js.php&quot;&gt;Include Facebook&amp;#8217;s JavaScript library&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;Write some JavaScript&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Steps 1-3 are fairly well documented in the links above. Step 4 is the interesting part. Take a look at the code below.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AK&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;apiKey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&amp;quot;de24e7cfd602218871fc8e30b3dd8a5f&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Facebook Connect is easy!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Updating from akahn.net&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.akahn.net&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;caption&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;So cool!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;image&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://akahn.net/images/shoes.jpg&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.akahn.net&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;FB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apiKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/xd_comm.html&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;FB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ensureInit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;FB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;streamPublish&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php/en_US&quot;&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;/js/facebook.js&quot;&gt;&lt;/script&gt;&lt;p&gt;What&amp;#8217;s going on here? First, I&amp;#8217;m creating an object, &lt;code&gt;AK&lt;/code&gt;, to store the various pieces of data I need. This includes an &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; key, the default message that the user will be posting to their feed, along with some other bits of text, and an image.&lt;/p&gt;
&lt;p&gt;I then get the &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; ready, using &lt;a href=&quot;http://wiki.developers.facebook.com/index.php/JS_API_M_FB.Init&quot;&gt;&lt;code&gt;FB.init&lt;/code&gt;&lt;/a&gt;, specifying my &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; key and the location of my cross-domain communication file.&lt;/p&gt;
&lt;p&gt;Then I make sure that the &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; has finished loading, using &lt;a href=&quot;http://wiki.developers.facebook.com/index.php/JS_API_M_FB.Bootstrap.EnsureInit&quot;&gt;&lt;code&gt;FB.ensureInit&lt;/code&gt;&lt;/a&gt;. I pass in a function, to be executed once the &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; has finished loading.&lt;/p&gt;
&lt;p&gt;In the function, I call &lt;a href=&quot;http://wiki.developers.facebook.com/index.php/FB.Connect.streamPublish&quot;&gt;&lt;code&gt;FB.Connect.streamPublish&lt;/code&gt;&lt;/a&gt;. I pass in the message and the attachment object that I defined earlier. If the user is logged in on Facebook, they&amp;#8217;re presented with a modal popup inviting them to post to their feed. If not, they&amp;#8217;re prompted to log in before they are invited to create a feed item. Try it out below:&lt;/p&gt;
&lt;p class=&quot;connect&quot;&gt;&lt;a class=&quot;connect&quot; href=&quot;http://www.facebook.com/sharer.php?u=http://akahn.net/2009/11/06/pretty-feed-items-with-facebook-connect.html&quot;&gt;Post to my Facebook wall!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And that&amp;#8217;s it! It takes a lot of setup just to make one little call to &lt;code&gt;FB.Connect.streamPublish&lt;/code&gt;. But the smooth user experience and the customized, pretty feed item make it all worthwhile.&lt;/p&gt;</content>
 </entry>
 
 
</feed>

