Hacker News new | comments | show | ask | jobs | submit login
API Quirks: a new blog series documenting weird web API behavior (zapier.com)
25 points by mikeknoop 1849 days ago | hide | past | web | 7 comments | favorite



I love this. I have a suggestion too. Reddit's REST API is pretty quirky because it's so tightly coupled with their own front end code. Here is a quote from the code that handles posting a comment (https://github.com/reddit/reddit/blob/master/r2/r2/controlle...):

     # remove any null listings that may be present
     jquery("#noresults").hide()
To be clear: that's Python you're reading. It's pretending to interact with the DOM. These calls get bundled up and sent back with the response for the frontend code to slavishly execute. The result is quite a schizophrenic API. On the one hand, you can get very nicely formatted JSON about data like so http://www.reddit.com/r/skateboarding.json. On the other hand, it's needlessly difficult to write code that can tell if a comment posted successfully or not when the response data looks like this:

   "jquery":[
      [0, 1, "call", ["#form-t3_iqhw5ili"]],
      [1, 2, "attr", "find"],
      [2, 3, "call", [".status"]],
      [3, 4, "attr", "hide"],
      [4, 5, "call", []],
      [5, 6, "attr", "html"],
      [6, 7, "call", [""]],
      [7, 8, "attr", "end"],
      [8, 9, "call", []],
      [1, 10, "attr", "find"],
      [10, 11, "call", ["textarea"]],
      [11, 12, "attr", "attr"],
      [12, 13, "call", ["rows", 3]],
      [13, 14, "attr", "html"],
      [14, 15, "call", [""]],
      [15, 16, "attr", "val"],
      [16, 17, "call", [""]],
      [0, 18, "attr", "insert_things"],
      [18, 19, "call", [
            [{
                  "data":{
                     "content":"<div class=\"thing id-t1_c25u9i3 even odd comment \" onclick=\"click_thing(this)\"><p class=\"parent\"><a name=\"c25u9i3\" ></a></p><div class=\"midcol likes\" ><div class=\"arrow upmod\" onclick=\"$(this).vote('f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0', null, event)\" ></div><div class=\"arrow down\" onclick=\"$(this).vote('f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0', null, event)\" ></div></div><div class=\"entry likes\"><div class=\"collapsed\" style='display:none'><a href=\"#\" class=\"expand\" onclick=\"return showcomment(this)\">[+]</a><a href=\"http://www.reddit.com/user/KerrickLong\" class=\"author gray submitter id-t2_4appr\" >KerrickLong</a><span class=\"userattrs\">&#32;[<a class=\"submitter\" title=\"submitter\" href=\"/r/MostlyHarmless/comments/iqhw5/changelog_mostly_harmless_v041_released/\">S</a>]</span>&#32;<span class=\"score dislikes\">-1 points</span><span class=\"score unvoted\">0 points</span><span class=\"score likes\">1 point</span>&#32;<time title=\"Fri Jul 15 16:57:16 2011 GMT\" datetime=\"2011-07-15T16:57:16.209277+00:00\">91 milliseconds</time>&#32;ago &nbsp;<a href=\"#\" class=\"expand\" onclick=\"return showcomment(this)\">(0 children)</a></div><div class=\"noncollapsed\" ><p class=\"tagline\"><a href=\"#\" class=\"expand\" onclick=\"return hidecomment(this)\">[&ndash;]</a><a href=\"http://www.reddit.com/user/KerrickLong\" class=\"author submitter id-t2_4appr\" >KerrickLong</a><span class=\"userattrs\">&#32;[<a class=\"submitter\" title=\"submitter\" href=\"/r/MostlyHarmless/comments/iqhw5/changelog_mostly_harmless_v041_released/\">S</a>]</span>&#32;<span class=\"score dislikes\">-1 points</span><span class=\"score unvoted\">0 points</span><span class=\"score likes\">1 point</span>&#32;<time title=\"Fri Jul 15 16:57:16 2011 GMT\" datetime=\"2011-07-15T16:57:16.209277+00:00\">91 milliseconds</time>&#32;ago</p><form action=\"#\" class=\"usertext\" onsubmit=\"return post_form(this, 'editusertext')\" id=\"form-t1_c25u9i38va\"><input type=\"hidden\" name=\"thing_id\" value=\"t1_c25u9i3\"/><div class=\"usertext-body\"><div class=\"md\"><p>Hey!</p><p><strong><a href=\"http://www.google.com/\">search!</a></strong></p></div>\n</div><div class=\"usertext-edit\" style=\"display: none\"><div><textarea rows=\"1\" cols=\"1\" name=\"text\" >test&#32;comment</textarea></div><div class=\"bottom-area\"><span class=\"help-toggle toggle\" style=\"display: none\"><a class=\"option active \" href=\"#\" tabindex=\"100\" onclick=\"return toggle(this, helpon, helpoff)\" >formatting help</a><a class=\"option \" href=\"#\">hide help</a></span><span class=\"error TOO_LONG field-text\" style=\"display:none\"></span><span class=\"error RATELIMIT field-ratelimit\" style=\"display:none\"></span><span class=\"error NO_TEXT field-text\" style=\"display:none\"></span><span class=\"error TOO_OLD field-parent\" style=\"display:none\"></span><span class=\"error DELETED_COMMENT field-parent\" style=\"display:none\"></span><span class=\"error DELETED_LINK field-parent\" style=\"display:none\"></span><span class=\"error USER_BLOCKED field-parent\" style=\"display:none\"></span><div class=\"usertext-buttons\"><button type=\"submit\" onclick=\"\" class=\"save\" style='display:none'>save</button><button type=\"button\" onclick=\"cancel_usertext(this)\" class=\"cancel\" style='display:none'>cancel</button><span class=\"status\"></span></div></div><table class=\"markhelp md\" style=\"display: none\"><tr style=\"background-color: #ffff99; text-align: center\"><td><em>you type:</em></td><td><em>you see:</em></td></tr><tr><td>*italics*</td><td><em>italics</em></td></tr><tr><td>**bold**</td><td><b>bold</b></td></tr><tr><td>[reddit!](http://reddit.com)</td><td><a href=\"http://reddit.com\">reddit!</a></td></tr><tr><td>* item 1<br/>* item 2<br/>* item 3</td><td><ul><li>item 1</li><li>item 2</li><li>item 3</li></ul></td></tr><tr><td>&gt; quoted text</td><td><blockquote>quoted text</blockquote></td></tr><tr><td>Lines starting with four spaces<br/>are treated like code:<br/><br/><span class=\"spaces\">&nbsp;&nbsp;&nbsp;&nbsp;</span>if 1 * 2 &lt 3:<br/><span class=\"spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>print \"hello, world!\"<br/></td><td>Lines starting with four spaces<br/>are treated like code:<br/><pre>if 1 * 2 &lt 3:<br/>&nbsp;&nbsp;&nbsp;&nbsp;print \"hello, world!\"</pre></td></tr><tr><td>~~strikethrough~~</td><td><strike>strikethrough</strike></td></tr><tr><td>super^script</td><td>super<sup>script</sup></td></tr></table></div></form><ul class=\"flat-list buttons\"><li class=\"first\"><a href=\"http://www.reddit.com/r/MostlyHarmless/comments/iqhw5/changelog_mostly_harmless_v041_released/c25u9i3\" class=\"bylink\" rel=\"nofollow\" >permalink</a></li><li><a class=\"edit-usertext\" href=\"javascript:void(0)\" onclick=\"return edit_usertext(this)\">edit</a></li><li><form class=\"toggle del-button\" action=\"#\" method=\"get\"><input type=\"hidden\" name=\"executed\" value=\"deleted\"/><span class=\"option active\"><a href=\"#\" onclick=\"return toggle(this)\">delete</a></span><span class=\"option error\">are you sure? &#32;<a href=\"javascript:void(0)\" class=\"yes\" onclick='change_state(this, \"del\", hide_thing)'>yes</a>&#32;/&#32;<a href=\"javascript:void(0)\" class=\"no\" onclick=\"return toggle(this)\">no</a></span></form></li><li><form action=\"/post/remove\" method=\"post\" class=\"state-button remove-button\"><input type=\"hidden\" name=\"executed\" value=\"removed\" /><span><a href=\"javascript:void(0)\" onclick=\"return change_state(this, 'remove');\">remove</a></span></form></li><li class=\"toggle\"><form method=\"post\" action=\"/post/distinguish\"><input type=\"hidden\" value=\"distinguishing...\" name=\"executed\"/><a href=\"javascript:void(0)\" onclick=\"return toggle_distinguish_span(this)\">distinguish</a><span class=\"option error\">distinguish this? &#32;<a href=\"javascript:void(0)\" onclick=\"return set_distinguish(this, 'yes')\">yes</a>&#32;/&#32;<a href=\"javascript:void(0)\" onclick=\"return set_distinguish(this, 'no')\">no</a>&#32; /&#32;<a class=\"nonbutton\" href=\"/help/moderation#Distinguishing\">help</a>&#32;</span></form></li><li><a class=\"\" href=\"javascript:void(0)\" onclick=\"return reply(this)\">reply</a></li></ul></div></div><div class=\"child\" ></div><div class=\"clearleft\"><!--IE6sux--></div></div><div class=\"clearleft\"><!--IE6sux--></div>",
                     "contentHTML":"<div class=\"md\"><p>Hey!</p><p><strong><a href=\"http://www.google.com/\">search!</a></strong></p></div>",
                     "contentText":"Hey!\n\n**[search!](http://www.google.com/)**",
                     "id":"t1_c25u9i3",
                     "link":"t3_iqhw5",
                     "parent":"t3_iqhw5",
                     "replies":""
                  },
                  "kind":"t1"
               }],
            false
         ]
      ],
      [0, 20, "call", ["#noresults"]],
      [20, 21, "attr", "hide"],
      [21, 22, "call",[]]
   ]
Edit: Didn't mean for this to come off as a pop at them. I know how this sort of thing happens and I know that feel.


Wow. That is definitely crazy. At least in the end the serialization is fairly straightforward.

Some of the worst API's we've seen are definitely due to lack of proper documentation (or completely undocumented features). Hopefully we can start to fill the information void with the help of the Google Bot's indexing prowess.


That is an interesting pattern. There are a few projects doing similar things: https://github.com/tblobaum/nodeQuery

I imagine there is enough content for a series like this to warrant guest posts (since we are biased towards paid SaaS web APIs).


Isn't that the non-public internal reddit API? They have proper APIs for other things, I think.


Write a post about MailChimp's PHP API...I dare you.


found today - facebook likes for network solutions is negative.


Is there something similar but just for shit APIs? I'm spending as much time writing an API for as I am implementing a library for TVDB because the API is so... just stupid. By time I'll be done with this it will cache from TVDB and be able to serve all of the content back in a SANE REST API rather than in the random URL, extract string, request url, get a zip with 3 conflicting xml files inside. Ugh.




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact

Search: