{"id":2846,"date":"2010-02-02T07:13:55","date_gmt":"2010-02-02T15:13:55","guid":{"rendered":"http:\/\/palblog.fxpal.com\/?p=2846"},"modified":"2010-02-02T00:58:10","modified_gmt":"2010-02-02T08:58:10","slug":"talking-with-twitter","status":"publish","type":"post","link":"https:\/\/blog.fxpal.net\/?p=2846","title":{"rendered":"Talking with Twitter"},"content":{"rendered":"<p>I&#8217;ve been messing with the Twitter <a title=\"Twitter Search API Method: search | Twitter API Wiki\" href=\"http:\/\/apiwiki.twitter.com\/Twitter-Search-API-Method%3A-search\" target=\"_blank\">search API<\/a>, and I am here to whine about it. Overall, it&#8217;s a great feature, but it&#8217;s interesting that it imposes costs on the third-party client that the Twitter interface seemingly doesn&#8217;t share. For example, I can run a search and get back a bunch of results. When I do it from the Twitter web page, it gives me the option of drilling down and showing conversations when they come up in search results.<\/p>\n<p>When I execute the same query using the API, however, there is no indication that a particular message was related to some other message in any way. Sure, I know who sent what to whom, but that&#8217;s not enough! Not only does the search API not tell me when a message is a reply, it doesn&#8217;t provide useful information to indicate a retweet, either.<\/p>\n<p><!--more-->Consider the following search result:<\/p>\n<p><a href=\"http:\/\/palblog.fxpal.com\/wp-content\/uploads\/2010\/02\/conversation-11.bmp\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-2848\" title=\"conversation-1\" src=\"http:\/\/palblog.fxpal.com\/wp-content\/uploads\/2010\/02\/conversation-11.bmp\" alt=\"Search results, showing conversation\" \/><\/a>How does Twitter know that this conversation took place? It must look at the metadata for each status independently (where conversations are tracked) because the search results themselves only represent the matching tweets. Here&#8217;s the relevant JSON for a single posting, as returned by Twitter:<\/p>\n<pre style=\"font-size: larger;\">{\"profile_image_url\":\"http:\/\/a3.twimg.com\/profile_images\/\r\n197774691\/yi-yi_normal.jpg\",\r\n\"created_at\":\"Mon, 01 Feb 2010 04:51:44 +0000\",\r\n\"from_user\":\"De_El\",\r\n\"to_user_id\":8386054,\r\n\"text\":\"@emancan Or are you saying he's just enough of a landscape\r\nfeature that pop should have recognized him somehow at the Grammys?\",\r\n\"id\":8485752574,\r\n\"from_user_id\":15947592,\r\n\"to_user\":\"Emancan\",\r\n\"geo\":null,\r\n\"iso_language_code\":\"en\",\r\n\"source\":\"&lt;a href=\"http:\/\/twitter.com\/\"&gt;web&lt;\/a&gt;\"}\r\n<\/pre>\n<p>The &#8220;inReplyToStatusId&#8221; field is nowhere to be found. So not only must the client go back to the server to get the user info (and it must use the screen name rather than an id because of a <a title=\"Search API &quot;from_user_id&quot; doesn't match up with the proper Twitter &quot;user_id&quot;\" href=\"http:\/\/code.google.com\/p\/twitter-api\/issues\/detail?id=214\" target=\"_blank\">bug<\/a> reported more than a year ago), but it must also, separately, get the status to understand whether it was part of a conversation. And it must do this one user or status message at a time, further decreasing the efficiency of evaluating the query.<\/p>\n<p>It is interesting to note, however, that Twitter&#8217;s conversation feature does not appear to rely on &#8220;inReplyToStatusId&#8221; fields in a status object, but rather seems to bring together posts between two people within a certain amount of time. I discovered this by manually fetching the metadata for each tweet in the above conversation, only to discover that some of the tweets didn&#8217;t have &#8220;inReplyToStatusId&#8221; fields set. To replicate the conversation in a third-party client, you would have to issue two queries, one &#8220;from: a to: b&#8221; and the other &#8220;from: b to: a&#8221; and then merge the results by time. This part seems reasonable, although it would be nice to be able to issue the conjunction: &#8220;(from: a to: b) OR (from: b to: a)&#8221;. Unfortunately, Twitter returns no results for such queries.<\/p>\n<p>Thus to build up a graph of who sent what to whom would be quite\u00a0 time-consuming. While Twitter may not want to suffer the cost of large bulk transfers, it ought to be possible for clients to be a bit more efficient in their communication. Perhaps a way of optionally specifying which fields the client is interested in would be a reasonable compromise. For example, I may not be interested in the URLs, in the language, or in the source of a tweet, but would like to have refers-to data instead. Furthermore, since search results often contain multiple tweets by the same user, throwing in a collection of user records into the search results would be more efficient than having to fetch all the extra data in independent requests.<\/p>\n<p>Overall, Twitter&#8217;s API is an excellent piece of infrastructure that is partly responsible for the large diversity of clients and applications based on Twitter. In some cases, however, it falls short of what seems reasonably useful.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve been messing with the Twitter search API, and I am here to whine about it. Overall, it&#8217;s a great feature, but it&#8217;s interesting that it imposes costs on the third-party client that the Twitter interface seemingly doesn&#8217;t share. For example, I can run a search and get back a bunch of results. When I [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[82],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/blog.fxpal.net\/index.php?rest_route=\/wp\/v2\/posts\/2846"}],"collection":[{"href":"https:\/\/blog.fxpal.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.fxpal.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.fxpal.net\/index.php?rest_route=\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.fxpal.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2846"}],"version-history":[{"count":9,"href":"https:\/\/blog.fxpal.net\/index.php?rest_route=\/wp\/v2\/posts\/2846\/revisions"}],"predecessor-version":[{"id":2857,"href":"https:\/\/blog.fxpal.net\/index.php?rest_route=\/wp\/v2\/posts\/2846\/revisions\/2857"}],"wp:attachment":[{"href":"https:\/\/blog.fxpal.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2846"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.fxpal.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2846"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.fxpal.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2846"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}