Upgrade to Pro — share decks privately, control downloads, hide ads and more …

User Experience Patterns for APIs

User Experience Patterns for APIs

Slides from RailsClub 2012 in Moscow.

7e19cd5486b5d6dc1ef90e671ba52ae0?s=128

Wynn Netherland

September 15, 2012
Tweet

Transcript

  1. WYNN NETHERLAND User Experience Patterns for APIs

  2. Howdy!

  3. Wynn Netherland My name is

  4. None
  5. None
  6. None
  7. .com

  8. None
  9. None
  10. I write API wrappers

  11. None
  12. None
  13. UX Patterns for APIs and anti-patterns ^

  14. Support curling PATTERN

  15. curl -i https://api.github.com/users/defunkt HTTP/1.1 200 OK Server: nginx Date: Wed,

    12 Sep 2012 14:07:43 GMT Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 200 OK Content-Length: 692 X-Content-Type-Options: nosniff X-RateLimit-Remaining: 4997 X-RateLimit-Limit: 5000 Cache-Control: public, s-maxage=60, max-age=60 Vary: Accept X-GitHub-Media-Type: github.beta ETag: "ef742caec0c19e2169ffb05e7d200d17" Last-Modified: Tue, 11 Sep 2012 02:52:21 GMT { "following": 212, "type": "User", "html_url": "https://github.com/defunkt", "location": "San Francisco", "hireable": true,
  16. curl -i -u pengwynn \ https://api.github.com/user

  17. curl -i -u pengwynn \ https://api.github.com/user include response headers

  18. curl -i -u pengwynn \ https://api.github.com/user use Basic Auth, prompt

    for password
  19. Security mazes ANTI-PATTERN

  20. None
  21. OAuth is painful. OAuth2 hurts less.

  22. None
  23. Insane URLs ANTI-PATTERN

  24. http://sandbox.api.shopping.com/publisher/ 3.0/rest/GeneralSearch? hybridSortType=relevance&productSortType=r elevance&offerSortType=store- name&productReviewSortType=review-date

  25. http://maps.googleapis.com/maps/api/ staticmap?center=Brooklyn+Bridge,New +York,NY&zoom=13&size=600x300&maptype=road map&markers=color:blue%7Clabel:S %7C40.702147,-74.015794&markers=color:gree n%7Clabel:G%7C40.711614,-74.012318 &markers=color:red%7Ccolor:red%7Clabel:C %7C40.718217,-73.998284&sensor=false

  26. Maximize the payload PATTERN

  27. { "uri": "/pengwynn/githubbers", "name": "GitHubbers", "full_name": "@pengwynn/githubbers", "description": "", "mode":

    "public", "user": { "id": 14100886, "favourites_count": 275, "profile_image_url": "http://a0.twimg.com/profile_ima...", "profile_background_tile": false, "profile_sidebar_fill_color": "DDEEF6", "verified": false, "location": "Denton, TX", "utc_offset": -21600, "name": "Wynn Netherland", "lang": "en", "is_translator": false, "default_profile": true, "profile_background_color": "C0DEED", "protected": false, "contributors_enabled": false, "time_zone": "Central Time (US & Canada)", "profile_background_image_url": "http://a0.twimg.com/images/themes/...", "profile_link_color": "0084B4", "description": "Christian, husband, father, GitHubber, Co-host...", "geo_enabled": true, "listed_count": 388, "show_all_inline_media": true, "notifications": false, "id_str": "14100886", "statuses_count": 7178, "profile_image_url_https": "https://si0.twimg.com/profile_images/2221455972/
  28. { "uri": "/pengwynn/githubbers", "name": "GitHubbers", "full_name": "@pengwynn/githubbers", "description": "", "mode":

    "public", "user": { "id": 14100886, "favourites_count": 275, "profile_image_url": "http://a0.twimg.com/profile_ima...", "profile_background_tile": false, "profile_sidebar_fill_color": "DDEEF6", "verified": false, "location": "Denton, TX", "utc_offset": -21600, "name": "Wynn Netherland", "lang": "en", "is_translator": false, "default_profile": true, "profile_background_color": "C0DEED", "protected": false, "contributors_enabled": false, "time_zone": "Central Time (US & Canada)", "profile_background_image_url": "http://a0.twimg.com/images/themes/...", "profile_link_color": "0084B4", "description": "Christian, husband, father, GitHubber, Co-host...", "geo_enabled": true, "listed_count": 388, "show_all_inline_media": true, "notifications": false, "id_str": "14100886", "statuses_count": 7178, "profile_image_url_https": "https://si0.twimg.com/profile_images/2221455972/ Full User object
  29. Rock the cache PATTERN

  30. curl -I https://api.github.com/users/defunkt HTTP/1.1 200 OK Server: nginx Date: Wed,

    12 Sep 2012 14:07:43 GMT Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 200 OK Content-Length: 692 X-Content-Type-Options: nosniff X-RateLimit-Remaining: 4997 X-RateLimit-Limit: 5000 Cache-Control: public, s-maxage=60, max-age=60 Vary: Accept X-GitHub-Media-Type: github.beta ETag: "ef742caec0c19e2169ffb05e7d200d17" Last-Modified: Tue, 11 Sep 2012 02:52:21 GMT
  31. curl -I https://api.github.com/users/defunkt HTTP/1.1 200 OK Server: nginx Date: Wed,

    12 Sep 2012 14:07:43 GMT Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 200 OK Content-Length: 692 X-Content-Type-Options: nosniff X-RateLimit-Remaining: 4997 X-RateLimit-Limit: 5000 Cache-Control: public, s-maxage=60, max-age=60 Vary: Accept X-GitHub-Media-Type: github.beta ETag: "ef742caec0c19e2169ffb05e7d200d17" Last-Modified: Tue, 11 Sep 2012 02:52:21 GMT
  32. curl -I https://api.github.com/users/defunkt HTTP/1.1 200 OK Server: nginx Date: Wed,

    12 Sep 2012 14:07:43 GMT Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 200 OK Content-Length: 692 X-Content-Type-Options: nosniff X-RateLimit-Remaining: 4997 X-RateLimit-Limit: 5000 Cache-Control: public, s-maxage=60, max-age=60 Vary: Accept X-GitHub-Media-Type: github.beta ETag: "ef742caec0c19e2169ffb05e7d200d17" Last-Modified: Tue, 11 Sep 2012 02:52:21 GMT Cache policy
  33. curl -I https://api.github.com/users/defunkt HTTP/1.1 200 OK Server: nginx Date: Wed,

    12 Sep 2012 14:07:43 GMT Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 200 OK Content-Length: 692 X-Content-Type-Options: nosniff X-RateLimit-Remaining: 4997 X-RateLimit-Limit: 5000 Cache-Control: public, s-maxage=60, max-age=60 Vary: Accept X-GitHub-Media-Type: github.beta ETag: "ef742caec0c19e2169ffb05e7d200d17" Last-Modified: Tue, 11 Sep 2012 02:52:21 GMT Fingerprint
  34. curl -I \ -H 'If-None-Match:"ef742caec0c19e2169ffb05e7d200d17" \ https://api.github.com/users/defunkt HTTP/1.1 304 Not

    Modified Server: nginx Date: Wed, 12 Sep 2012 15:51:39 GMT Connection: keep-alive Status: 304 Not Modified X-RateLimit-Limit: 5000 X-Content-Type-Options: nosniff Vary: Accept ETag: "ef742caec0c19e2169ffb05e7d200d17" X-RateLimit-Remaining: 4997 Last-Modified: Wed, 12 Sep 2012 01:38:14 GMT Cache-Control: public, s-maxage=60, max-age=60
  35. curl -H 'If-None-Match:"ef742caec0c19e2169ffb05e7d200d17" \ https://api.github.com/users/defunkt HTTP/1.1 304 Not Modified Server:

    nginx Date: Wed, 12 Sep 2012 15:51:39 GMT Connection: keep-alive Status: 304 Not Modified X-RateLimit-Limit: 5000 X-Content-Type-Options: nosniff Vary: Accept ETag: "ef742caec0c19e2169ffb05e7d200d17" X-RateLimit-Remaining: 4997 Last-Modified: Wed, 12 Sep 2012 01:38:14 GMT Cache-Control: public, s-maxage=60, max-age=60
  36. $ curl -i https://api.github.com/user HTTP/1.1 200 OK Cache-Control: private, max-age=60

    ETag: "644b5b0155e6404a9cc4bd9d8b1ae730" Last-Modified: Thu, 05 Jul 2012 15:31:30 GMT Status: 200 OK Vary: Accept, Authorization, Cookie X-RateLimit-Limit: 5000 X-RateLimit-Remaining: 4996 $ curl -i https://api.github.com/user -H "If-Modified-Since: Thu, 05 Jul 2012 15:31:30 GMT" HTTP/1.1 304 Not Modified Cache-Control: private, max-age=60 Last-Modified: Thu, 05 Jul 2012 15:31:30 GMT Status: 304 Not Modified Vary: Accept, Authorization, Cookie X-RateLimit-Limit: 5000 X-RateLimit-Remaining: 4996 $ curl -i https://api.github.com/user -H 'If-None-Match: "644b5b0155e6404a9cc4bd9d8b1ae730"' HTTP/1.1 304 Not Modified Cache-Control: private, max-age=60 ETag: "644b5b0155e6404a9cc4bd9d8b1ae730" Last-Modified: Thu, 05 Jul 2012 15:31:30 GMT Status: 304 Not Modified Vary: Accept, Authorization, Cookie X-RateLimit-Limit: 5000 X-RateLimit-Remaining: 4996
  37. Dogfood it PATTERN

  38. Build something meaningful with your API.

  39. Build something meaningful with your API. Janky

  40. Build something meaningful with your API. Janky Heaven

  41. Build something meaningful with your API. Janky Heaven Monitors

  42. Build something meaningful with your API. Janky Team Heaven Monitors

  43. Build something meaningful with your API. Janky Team Hire Heaven

    Monitors
  44. Build something meaningful with your API. Janky Team Hire Heaven

    Monitors The Setup™
  45. Build something meaningful with your API. Janky Team Hire Heaven

    Monitors The Setup™ Graph Store
  46. How GitHub uses the GitHub API.

  47. How GitHub uses the GitHub API. AuthN

  48. How GitHub uses the GitHub API. AuthN AuthZ

  49. How GitHub uses the GitHub API. AuthN AuthZ Merging

  50. How GitHub uses the GitHub API. AuthN AuthZ Merging Commit

    Status
  51. How GitHub uses the GitHub API. AuthN AuthZ Merging Commit

    Status GFM
  52. Oh, and native apps.

  53. Oh, and native apps. GitHub for Mac

  54. Oh, and native apps. GitHub for Mac GitHub for Windows

  55. PATTERN Use HTTP status codes

  56. HTTP/1.1 200 OK Server: nginx Date: Wed, 12 Sep 2012

    14:07:43 GMT Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 200 OK ETag: "ef742caec0c19e2169ffb05e7d200d17" Last-Modified: Tue, 11 Sep 2012 02:52:21 GMT { "error_code": 1234, "error": "User not found" }
  57. HTTP/1.1 404 Not Found Server: nginx Date: Wed, 12 Sep

    2012 14:07:43 GMT Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 404 Not Found
  58. Confusing header with body ANTI-PATTERN

  59. Harsh rate limits ANTI-PATTERN

  60. $ curl -i https://api.github.com/users/ whatever? client_id=xxxxxxxxxxxxxx&client_secret=yyy yyyyyyyyyyyyyyyyyy HTTP/1.1 200 OK

    Status: 200 OK X-RateLimit-Limit: 12500 X-RateLimit-Remaining: 11966
  61. Announce breaking changes PATTERN

  62. None
  63. Make documentation obvious PATTERN

  64. None
  65. None
  66. None
  67. None
  68. Create awesome guides PATTERN

  69. None
  70. None
  71. None
  72. Consoles PATTERN

  73. None
  74. None
  75. ANTI-PATTERN Endless terms of service changes

  76. Inconsistency ANTI-PATTERN

  77. POST /gists/:id/fork POST /repos/:user/:repo/merges

  78. Fast, transparent support PATTERN

  79. None
  80. Free samples PATTERN

  81. None
  82. Mashup friendly PATTERN

  83. JSONP

  84. $ curl https://api.github.com?callback=foo foo({ "meta": { "status": 200, "X-RateLimit-Limit": "5000",

    "X-RateLimit-Remaining": "4966", "Link": [ // pagination headers and other links ["https://api.github.com?page=2", {"rel": "next"}] ] }, "data": { // the data } })
  85. CORS

  86. $ curl -i https://api.github.com \ -H "Origin: http://calendaraboutnothing.com" HTTP/1.1 302

    Found Access-Control-Allow-Origin: http://calendaraboutnothing.com Access-Control-Expose-Headers: Link, X-RateLimit-Limit, X- RateLimit-Remaining, X-OAuth-Scopes, X-Accepted-OAuth-Scopes Access-Control-Allow-Credentials: true
  87. $ curl -i https://api.github.com \ -H "Origin: http://calendaraboutnothing.com" -X OPTIONS

    HTTP/1.1 204 No Content Access-Control-Allow-Origin: http://calendaraboutnothing.com Access-Control-Allow-Headers: Authorization, X-Requested-With Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE Access-Control-Expose-Headers: Link, X-RateLimit-Limit, X- RateLimit-Remaining, X-OAuth-Scopes, X-Accepted-OAuth-Scopes Access-Control-Max-Age: 86400 Access-Control-Allow-Credentials: true
  88. Streaming PATTERN

  89. Persistent HTTP

  90. Updates as they happen

  91. None
  92. Thanks!