Ce diaporama a bien été signalé.
Le téléchargement de votre SlideShare est en cours. ×

HTTP and Your Angry Dog

Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Prochain SlideShare
using python module: doctest
using python module: doctest
Chargement dans…3
×

Consultez-les par la suite

1 sur 200 Publicité

Plus De Contenu Connexe

Diaporamas pour vous (20)

Publicité

Similaire à HTTP and Your Angry Dog (20)

Plus récents (20)

Publicité

HTTP and Your Angry Dog

  1. 1. HTTP & Your Angry Dog ZendCon 2014 Ross Tuck
  2. 2. Freerange Codemonkey Know-It-All Hot-Air Balloon
  3. 3. @rosstuck rosstuck.com
  4. 4. Today's topic:
  5. 5. Dogs
  6. 6. HTTP & Dogs
  7. 7. The Agenda
  8. 8. Basics
  9. 9. Request Response Client Server
  10. 10. Request POST /gists HTTP/1.1 Authorization: Basic xxxxxxxx Host: api.github.com Content-Length: 146 { "description": "the description for this gist", "public": false, "files": { ...
  11. 11. Request POST /gists HTTP/1.1 Authorization: Basic xxxxxxxx Host: api.github.com Content-Length: 146 { "description": "the description for this gist", "public": false, "files": { ... 2 Parts
  12. 12. Request POST /gists HTTP/1.1 Authorization: Basic xxxxxxxx Host: api.github.com Content-Length: 146 { "description": "the description for this gist", "public": false, "files": { ... The body
  13. 13. Request POST /gists HTTP/1.1 Authorization: Basic xxxxxxxx Host: api.github.com Content-Length: 146 <!DOCTYPE html> <html> <head> <meta charset='utf-8'> <title>My application</title> ... The body
  14. 14. Request POST /gists HTTP/1.1 Authorization: Basic xxxxxxxx Host: api.github.com Content-Length: 146 { "description": "the description for this gist", "public": false, "files": { ... The body
  15. 15. Request POST /gists HTTP/1.1 Authorization: Basic xxxxxxxx Host: api.github.com Content-Length: 146 { "description": "the description for this gist", "public": false, "files": { ...
  16. 16. Request POST /gists HTTP/1.1 Authorization: Basic xxxxxxxx Host: api.github.com Content-Length: 146 { "description": "the description for this gist", "public": false, "files": { ... The headers
  17. 17. Request POST /gists HTTP/1.1 Authorization: Basic xxxxxxxx Host: api.github.com Content-Length: 146 { "description": "the description for this gist", "public": false, "files": { ... The good stuf
  18. 18. Request POST /gists HTTP/1.1 Authorization: Basic xxxxxxxx Host: api.github.com Content-Length: 146 { "description": "the description for this gist", "public": false, "files": { ...
  19. 19. Request POST /gists HTTP/1.1 Authorization: Basic xxxxxxxx Host: api.github.com Content-Length: 146 { "description": "the description for this gist", "public": false, "files": { ... GET, POST, PUT, DELETE
  20. 20. Request Relative URL POST /gists HTTP/1.1 Authorization: Basic xxxxxxxx Host: api.github.com Content-Length: 146 { "description": "the description for this gist", "public": false, "files": { ... HTTP version
  21. 21. Request POST /gists HTTP/1.1 Authorization: Basic xxxxxxxx Host: api.github.com Content-Length: 146 { "description": "the description for this gist", "public": false, "files": { ... Key/Value pairs
  22. 22. Request POST /gists HTTP/1.1 Authorization: Basic xxxxxxxx Host: api.github.com Content-Length: 146 { "description": "the description for this gist", "public": false, "files": { ...
  23. 23. Response HTTP/1.1 201 Created Date: Sun, 09 Sep 2012 11:42:41 GMT Content-Length: 1848 Location: https://api.github.com/gists/a43a0cf58 { "description": "the description for this gist", "comments": 0, "created_at": "2012-09-09T11:42:40Z", ... Status code
  24. 24. • 2xx • 3xx • 4xx • 5xx OK! Over there! Client screwed up! Server screwed up!
  25. 25. Content Negotiation
  26. 26. Request GET /dogs/corgi HTTP/1.1 Host: api.example.com
  27. 27. Response HTTP/1.1 200 OK Date: Sun, 26 Aug 2012 18:00:43 GMT { "cute": true, "big": false, "data_dog": true }
  28. 28. Response HTTP/1.1 200 OK Date: Sun, 26 Aug 2012 18:00:43 GMT <dog breed="corgi"> <cute>true</cute> <data capacity="on" /> </dog>
  29. 29. Request GET /dogs/corgi HTTP/1.1 Host: api.example.com
  30. 30. Request GET /dogs/corgi.json HTTP/1.1 Host: api.example.com
  31. 31. /dogs/corgi.json !== /dogs/corgi.xml
  32. 32. Imagine the URL as your primary key.
  33. 33. Request GET /dogs/corgi HTTP/1.1 Host: api.example.com
  34. 34. Request GET /dogs/corgi?_format=json HTTP/1.1 Host: api.example.com
  35. 35. Request POST /dogs/corgi?_format=json HTTP/1.1 Host: api.example.com
  36. 36. Request GET /dogs/corgi HTTP/1.1 Host: api.example.com
  37. 37. Request GET /dogs/corgi HTTP/1.1 Host: api.example.com Accept: application/json
  38. 38. More POWAH
  39. 39. Request GET /dogs/corgi HTTP/1.1 Host: api.example.com Accept: application/json
  40. 40. Request GET /dogs/corgi HTTP/1.1 Host: api.example.com Accept: application/json, application/xml How do I choose?
  41. 41. Request GET /dogs/corgi HTTP/1.1 Host: api.example.com Accept: application/json, application/xml
  42. 42. Response HTTP/1.1 200 OK Date: Sun, 26 Aug 2012 18:00:43 GMT Content-Type: application/json { "cute": true, "big": false, "data_dog": true }
  43. 43. Nifty.
  44. 44. Request GET /dogs/corgi HTTP/1.1 Host: api.example.com Accept: application/json, application/xml
  45. 45. text/html, text/plain
  46. 46. text/html;key=value, text/plain
  47. 47. text/html;key=value;foo=bar, text/plain
  48. 48. text/html, text/plain
  49. 49. Quality (Default 1.0) text/html, text/plain;q=0.5
  50. 50. text/html, text/plain;q=0.5, text/*;q=0.1 Wildcards
  51. 51. Anything at all text/html, text/plain;q=0.5, */*;q=0.1
  52. 52. Accept Headers Little weird...
  53. 53. But not so scary.
  54. 54. text/html,application/xhtml+xml, application/xml;q=0.9,*/*;q=0.8
  55. 55. Cool...
  56. 56. What the heck is it good for?
  57. 57. Accept is a “Pattern”
  58. 58. Accept-Language Accept-Encoding Accept-Charset Accept-Ranges
  59. 59. Content-Language Content-Encoding (works differently) Content-Range
  60. 60. /dog/corgi Resource vs Representation JSON, Dutch, Gzipped, /dog/corgi
  61. 61. Resource vs Representation
  62. 62. Best way to version your API. Arguably. Right now.
  63. 63. /v1/dogs/corgi
  64. 64. Accept: application/vnd.dogipedia-v1+json
  65. 65. Accept: application/vnd.dogipedia-v2+json
  66. 66. Vary
  67. 67. GET /dogs/corgi HTTP/1.1 Host: api.example.com Client Server
  68. 68. GET /dogs/corgi HTTP/1.1 Host: api.example.com Client Server
  69. 69. GET /dogs/corgi HTTP/1.1 Host: api.example.com Client Proxy Server
  70. 70. GET /dogs/corgi HTTP/1.1 Host: api.example.com Accept: application/json, text/plain User-Species: cat Client Proxy Server
  71. 71. Same URL. Different output. WTF should I return?
  72. 72. GET /dogs/corgi HTTP/1.1 Host: api.example.com Accept: application/json, text/plain User-Species: cat Client Proxy Server
  73. 73. Client Proxy Server
  74. 74. Here's how. Hint: Involves the Vary header!
  75. 75. /dogs/corgi Accept: application/json, text/plain User-Species: cat Client Proxy Server
  76. 76. Response HTTP/1.1 200 OK Date: Sun, 26 Aug 2012 18:00:43 GMT Content-Type: application/json Vary: Accept {“json”: “omgz”}
  77. 77. URL and Accept? Okay, I got this. Client Proxy Server
  78. 78. Some time later...
  79. 79. /dogs/corgi Accept: application/json, text/plain User-Species: aardvark Client Proxy Server
  80. 80. Valid cache. I has it. Client Proxy Server
  81. 81. ZZZ Z Z Z Client Proxy Server
  82. 82. Response HTTP/1.1 200 OK Date: Sun, 26 Aug 2012 18:00:43 GMT Content-Type: application/json Vary: Accept {“json”: “omgz”}
  83. 83. Response HTTP/1.1 200 OK Date: Sun, 26 Aug 2012 18:00:43 GMT Content-Type: application/json Vary: Accept, User-Species {“json”: “omgz”}
  84. 84. Response HTTP/1.1 200 OK Date: Sun, 26 Aug 2012 18:00:43 GMT Content-Type: application/json Vary: Accept, User-Species {“json”: “dogs rule, cats drool”}
  85. 85. Request headers. Not Response!
  86. 86. Bad Reputation? 2 Reasons
  87. 87. 1. Accept-Encoding -Language
  88. 88. 2. Internet Explorer
  89. 89. Caching
  90. 90. Expires Pragma Cache-Control
  91. 91. Expires Pragma Cache-Control
  92. 92. Expires Cache-Control HTTP 1.0 HTTP 1.1
  93. 93. Response HTTP/1.1 200 OK Expires: Wed, 29 Oct 2014 22:00:00 GMT {“herp”: “derp”}
  94. 94. Response HTTP/1.1 200 OK Cache-Control: max-age=120 {“herp”: “derp”}
  95. 95. Response HTTP/1.1 200 OK Cache-Control: max-age=120
  96. 96. Expires Cache-Control HTTP 1.0 HTTP 1.1
  97. 97. Response HTTP/1.1 200 OK Cache-Control: max-age=120 {“herp”: “derp”}
  98. 98. Response HTTP/1.1 200 OK Cache-Control: max-age=120, s-maxage=120 {“herp”: “derp”} Dude, Where's my dash?
  99. 99. public private no-store no-cache no-transform must-revalidate proxy-revalidate
  100. 100. Much better than me. Mark Nottingham's Caching Tutorial http://www.mnot.net/cache_docs/
  101. 101. Conditional Requests
  102. 102. Conditional Requests
  103. 103. The Part About ETags
  104. 104. Conditional Requests
  105. 105. Request DELETE /ross/reputation HTTP/1.1 Host: api.joind.in If-Talk-Quality: Crap
  106. 106. if ($talkQuality === 'Crap') { real code delete($rossReputation); Not } Server
  107. 107. What kind of conditions?
  108. 108. If-Match If-None-Match If-Modified-Since If-Unmodified-Since If-Range ETags Datetimes Either
  109. 109. Wait a second, Ross. Audience
  110. 110. What the heck is an ETag?
  111. 111. A string. Any string.
  112. 112. One rule:
  113. 113. Represent the current state.
  114. 114. “14” “a381bedb5d4478053eb04be35f8798dd” “winnie-the-pooh”
  115. 115. ...for the current representation.
  116. 116. etag(“v14-json-en”) !== etag(“v14-xml-en”) Don't cross the streams Server
  117. 117. Last Modified Date sounds easier... Audience
  118. 118. One second of precision Wed, 15 Nov 1995 04:58:08 GMT
  119. 119. Caching With Conditionals
  120. 120. Use Case
  121. 121. Request GET /gists/3481910 HTTP/1.1 Host: api.github.com Accept: */*
  122. 122. Response HTTP/1.1 200 OK Server: nginx/1.0.13 Date: Sun, 26 Aug 2012 18:00:43 GMT Vary: Accept ETag: "f4e15911542b92b44bb38186e71cc8f5" "history": [ { "version": "529f6311d5518977534b6e1fd313...", ...
  123. 123. Response ... "user": { "gravatar_id": "c26bfcbd5f786591e036fa0", "avatar_url": "https://secure.gravatar...", "login": "rosstuck", "url": "https://api.github.com/users/rosstuck", "id": 146766 }, "change_status": { "additions": 1, "deletions": 0, "total": 1 },
  124. 124. Response "url": "https://api.github.com/gists/348...", "committed_at": "2012-08-26T17:40:03Z" } ], "git_pull_url": "git://gist.github.com/34819...", "forks": [ ], "html_url": "https://gist.github.com/3481910", "git_push_url": "git@gist.github.com:3481910.git", "comments": 0, "user": {
  125. 125. Response HTTP/1.1 200 OK Server: nginx/1.0.13 Date: Sun, 26 Aug 2012 18:00:43 GMT Vary: Accept ETag: "f4e15911542b92b44bb38186e71cc8f5" { "history": [ { "version": "529f6311d5518970903cb5427534b6e1fd313aca", "user": { "gravatar_id": "c26bfcbd5f786591e036fa0958a11e8b", "avatar_url": "https://secure.gravatar.com/avatar/c26bfcbd5f786591e036fa0958a11e8b?d=https://a2... "login": "rosstuck", "url": "https://api.github.com/users/rosstuck", "id": 146766 }, "change_status": { "additions": 1, "deletions": 0, "total": 1 }, "url": "https://api.github.com/gists/3481910/529f6311d5518970903cb5427534b6e1fd313aca", "committed_at": "2012-08-26T17:40:03Z" } ], "git_pull_url": "git://gist.github.com/3481910.git", "forks": [ ], "html_url": "https://gist.github.com/3481910", "git_push_url": "git@gist.github.com:3481910.git", "comments": 0, "user": { "gravatar_id": "c26bfcbd5f786591e036fa0958a11e8b", "avatar_url": "https://secure.gravatar.com/avatar/c26bfcbd5f78659....",} "login": "rosstuck", "url": "https://api.github.com/users/rosstuck", "id": 146766 }, "public": true, "created_at": "2012-08-26T17:40:03Z", "files": { "gistfile1.txt": { "type": "text/plain", "filename": "gistfile1.txt", "raw_url": "https://gist.github.com/raw/3481910/8b6946739e8098408ee3af96... "content": "Hello PFC!", "language": null, "size": 10 } }, "description": "", "url": "https://api.github.com/gists/3481910", "updated_at": "2012-08-26T17:40:03Z", "id": "3481910" }
  126. 126. Request GET /gists/3481910 HTTP/1.1 Host: api.github.com Accept: */* If-None-Match: "f4e15911542b92b44bb38186e71cc8f5"
  127. 127. Response HTTP/1.1 304 Not Modified Server: nginx/1.0.13 Date: Sun, 26 Aug 2012 18:00:43 GMT Vary: Accept ETag: "f4e15911542b92b44bb38186e71cc8f5"
  128. 128. Response HTTP/1.1 304 Not Modified Server: nginx/1.0.13 Date: Sun, 26 Aug 2012 18:00:43 GMT Vary: Accept ETag: "f4e15911542b92b44bb38186e71cc8f5"
  129. 129. Response HTTP/1.1 304 Not Modified Server: nginx/1.0.13 Date: Sun, 26 Aug 2012 18:00:43 GMT Vary: Accept ETag: "f4e15911542b92b44bb38186e71cc8f5" No giant body!
  130. 130. Caching. You has it.
  131. 131. Request GET /gists/3481910 HTTP/1.1 Host: api.github.com Accept: */* If-None-Match: "a381bedb5d4478053eb04be35f8798dd"
  132. 132. Request GET /gists/3481910 HTTP/1.1 Host: api.github.com Accept: */* If-None-Match: "ross-is-a-poo-poo-head"
  133. 133. Response HTTP/1.1 200 OK Server: nginx/1.0.13 Date: Sun, 26 Aug 2012 18:00:43 GMT Vary: Accept ETag: "f4e15911542b92b44bb38186e71cc8f5" "history": [ { "version": "529f6311d5518977534b6e1fd313...",
  134. 134. Recap
  135. 135. No ETag Old ETag Matching ETag Full Body Full Body No Body → → →
  136. 136. ...on supported servers.
  137. 137. Why?
  138. 138. Parsing Bandwidth Response time Probably .Maybe
  139. 139. However...
  140. 140. “The fastest request is one you don't make.” - Jesus
  141. 141. More Fun With ETags
  142. 142. Optimistic Concurrency Control “Record Versioning”
  143. 143. Request
  144. 144. Request GET /gists/3481910 HTTP/1.1 Host: api.github.com Accept: */* If-None-Match: "f4e15911542b92b44bb38186e71cc8f5"
  145. 145. Request PATCH /gists/3481910 HTTP/1.1 Host: api.github.com Accept: */* If-None-Match: "f4e15911542b92b44bb38186e71cc8f5"
  146. 146. Request PATCH /gists/3481910 HTTP/1.1 Host: api.github.com Accept: */* If-Match: "f4e15911542b92b44bb38186e71cc8f5"
  147. 147. Request PATCH /gists/3481910 HTTP/1.1 Host: api.github.com Accept: */* If-Match: "f4e15911542b92b44bb38186e71cc8f5" { "description": "cheese om nom nom" }
  148. 148. Response
  149. 149. Response HTTP/1.1 200 OK Server: nginx/1.0.13 Date: Sat, 01 Sep 2012 14:01:38 GMT ETag: "899b76047a5e68445668374c2e0faa32" { "description": "cheese om nom nom", "user": { "login": "rosstuck", ...
  150. 150. It works.
  151. 151. So what?
  152. 152. What if I send something...
  153. 153. Request PATCH /gists/3481910 HTTP/1.1 Host: api.github.com Accept: */* If-Match: "899b76047a5e68445668374c2e0faa32" { "description": "cheese om nom nom" }
  154. 154. Request PATCH /gists/3481910 HTTP/1.1 Host: api.github.com Accept: */* If-Match: "stay-puft-marshmellow-dog!" { "description": "cheese om nom nom" }
  155. 155. Response HTTP/1.1 412 Precondition Failed Server: nginx/1.0.13 Date: Sun, 26 Aug 2012 18:00:43 GMT
  156. 156. Response
  157. 157. Server if (“stay-puft-marshmellow-dog” == “f4e1591..”) { patchTheRecord(); }
  158. 158. Server if (“stay-puft-marshmellow-dog” == “f4e1591..”) { patchTheRecord(); } else { sendScary412Message(); }
  159. 159. Your ETag is out of date.
  160. 160. “Two guys on the same record” problem
  161. 161. Scary Precondition Error pt. 2
  162. 162. Disclaimer New Stuff Ahead
  163. 163. Request DELETE /gists/3481910 HTTP/1.1 Host: api.github.com
  164. 164. Response HTTP/1.1 428 Precondition Required Server: nginx/1.0.13 Date: Sun, 26 Aug 2012 18:00:43 GMT
  165. 165. Am I operating on the latest version?
  166. 166. Request DELETE /gists/3481910 HTTP/1.1 Host: api.github.com
  167. 167. Request DELETE /gists/3481910 HTTP/1.1 Host: api.github.com If-Match: "f4e15911542b92b44bb38186e71cc8f5"
  168. 168. Response HTTP/1.1 204 No Content Server: nginx/1.0.13 Date: Sun, 26 Aug 2012 18:00:43 GMT
  169. 169. Look before you leap.
  170. 170. Tooling
  171. 171. Epilogue: HTTP & Dogs
  172. 172. Content Negotiation Vary Caching Preconditions
  173. 173. Treat it like your framework.
  174. 174. Questions?
  175. 175. Resources • RFC 7231 –Sections 4 - 7 • http://redbot.org/ • http://mnot.net/cache_docs/ • http://charlesproxy.com/ • http://guzzlephp.org/
  176. 176. Image Credits • http://www.sxc.hu/photo/555539 • http://www.flickr.com/photos/thedalogs/2953136078/ • http://www.sxc.hu/photo/678952 • http://www.flickr.com/photos/designgate/8317884432/ • http://www.flickr.com/photos/barretthall/3289317664/ • http://www.flickr.com/photos/binaryape/3702275400/lightbox/ • http://www.flickr.com/photos/istolethetv/2956799679/in/photostream/ • http://theflashbackspodcast.blogspot.nl/2012/01/30-day-film-challenge-day-8.html • http://www.flickr.com/photos/jonomueller/6906420190/ • http://www.flickr.com/photos/cookbookman/6175752147 • http://www.flickr.com/photos/creativedc/2913123330/ • http://www.flickr.com/photos/epc/44053757/ • http://www.flickr.com/photos/soggydan/4698849104/ • http://www.flickr.com/photos/owldreams/4430175427/ • http://www.flickr.com/photos/piddleville/2499539542/ • http://www.flickr.com/photos/danja/5665671907/ • http://www.flickr.com/photos/cradlehall/3574160744/ • http://www.flickr.com/photos/ironypoisoning/7114801437/ • http://www.flickr.com/photos/piddleville/2499539542/lightbox/ • http://everydayidrawadog.blogspot.nl/2009_02_01_archive.html
  177. 177. joind.in/12071 Ross Tuck rosstuck.com @rosstuck

×