Slide 1

Slide 1 text

[ LESS HYPE, MORE MEDIA, PLEASE ] HYPERMEDIA APIs

Slide 2

Slide 2 text

WYNNNETHERLAND

Slide 3

Slide 3 text

@pengwynn

Slide 4

Slide 4 text

@pengwynn

Slide 5

Slide 5 text

WYNN.FM

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

I write API wrappers.

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

Wynn Netherland Flightless waterfowl

Slide 16

Slide 16 text

Wynn Netherland Defacto API Evangelist

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

Our industry loves buzzwords.

Slide 19

Slide 19 text

“Nice site. Is it RESPONSIVE?”

Slide 20

Slide 20 text

“Nice database. Is it SCHEMALESS?”

Slide 21

Slide 21 text

“Nice API. Is it HYPERMEDIA-DRIVEN?”

Slide 22

Slide 22 text

Nice questions. HACKER NEWS much?

Slide 23

Slide 23 text

WHAT THE HECK IS HYPERMEDIA?

Slide 24

Slide 24 text

>

Slide 25

Slide 25 text

hubot wiki me hypermedia Hypermedia is used as a logical extension of the term hypertext in which graphics, audio, video, plain text and hyperlinks intertwine to create a generally non-linear medium of information. This contrasts with the broader term multimedia, which may be used to describe non-interactive linear presentations as well as hypermedia. It is also related to the field of electronic literature. The term was first used in a 1965 article by Ted Nelson. https://en.wikipedia.org/wiki/Hypermedia >

Slide 26

Slide 26 text

hubot wiki me hypermedia Hypermedia is used as a logical extension of the term hypertext in which graphics, audio, video, plain text and hyperlinks intertwine to create a generally non-linear medium of information. This contrasts with the broader term multimedia, which may be used to describe non-interactive linear presentations as well as hypermedia. It is also related to the field of electronic literature. The term was first used in a 1965 article by Ted Nelson. https://en.wikipedia.org/wiki/Hypermedia >

Slide 27

Slide 27 text

hypermedia Hypermedia is used as a logical extension of the term hypertext in which graphics, audio, video, plain text and hyperlinks intertwine to create a generally non-linear medium of information.

Slide 28

Slide 28 text

hypermedia Hypermedia is used as a logical extension of the term hypertext in which graphics, audio, video, plain text and hyperlinks intertwine to create a generally non-linear medium of information.

Slide 29

Slide 29 text

hypertext Hypertext is text displayed on a computer display or other electronic device with references (hyperlinks) to other text that the reader can immediately access, usually by a mouse click, keypress sequence or by touching the screen.

Slide 30

Slide 30 text

hypertext Hypertext is text displayed on a computer display or other electronic device with references (hyperlinks) to other text that the reader can immediately access, usually by a mouse click, keypress sequence or by touching the screen.

Slide 31

Slide 31 text

hyperlink In computing, a hyperlink (or link) is a reference to data that the reader can directly follow, or that is followed automatically. A hyperlink points to a whole document or to a specific element within a document.

Slide 32

Slide 32 text

hyperlink In computing, a hyperlink (or link) is a reference to data that the reader can directly follow, or that is followed automatically. A hyperlink points to a whole document or to a specific element within a document.

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

HATEOAS

Slide 37

Slide 37 text

HATEOAS Rhymes with Cheerios

Slide 38

Slide 38 text

HATEOAS Rhymes with Cheerios

Slide 39

Slide 39 text

HATEOAS

Slide 40

Slide 40 text

HATEOAS A REST client enters a REST application through a simple fixed URL. *

Slide 41

Slide 41 text

HATEOAS A REST client enters a REST application through a simple fixed URL. * All future actions the client may take are discovered within resource representations returned from the server. *

Slide 42

Slide 42 text

HATEOAS A REST client enters a REST application through a simple fixed URL. * All future actions the client may take are discovered within resource representations returned from the server. * The media types used for these representations, and the link relations they may contain, are standardized. *

Slide 43

Slide 43 text

A SIMPLE EXAMPLE

Slide 44

Slide 44 text

$ curl https://status.github.com/api.json

Slide 45

Slide 45 text

$ curl https://status.github.com/api.json API root, our simple, fixed URL

Slide 46

Slide 46 text

$ curl https://status.github.com/api.json {"status_url":"https://status.github.com/api/ status.json","messages_url":"https://status.github.com/ api/messages.json","last_message_url":"https:// status.github.com/api/last-message.json"} Resource representation

Slide 47

Slide 47 text

$ curl https://status.github.com/api.json {"status_url":"https://status.github.com/api/ status.json","messages_url":"https://status.github.com/ api/messages.json","last_message_url":"https:// status.github.com/api/last-message.json"} Link relation

Slide 48

Slide 48 text

$ curl https://status.github.com/api.json \ | jq -r '.status_url' https://status.github.com/api/status.json

Slide 49

Slide 49 text

$ curl https://status.github.com/api.json \ | jq -r '.status_url' https://status.github.com/api/status.json

Slide 50

Slide 50 text

$ curl https://status.github.com/api.json \ | jq -r '.status_url' | xargs curl Follow link relation

Slide 51

Slide 51 text

$ curl https://status.github.com/api.json \ | jq -r '.status_url' | xargs curl {"status":"good","last_updated":"2013-02-27T21:31:55Z"}

Slide 52

Slide 52 text

$ curl https://status.github.com/api.json \ | jq -r '.status_url' | xargs curl {"status":"good","last_updated":"2013-02-27T21:31:55Z"}

Slide 53

Slide 53 text

$ curl https://status.github.com/api.json \ | jq -r '.status_url' | xargs curl \ | jq -r '.status'

Slide 54

Slide 54 text

DETOUR

Slide 55

Slide 55 text

brew install jq

Slide 56

Slide 56 text

THE REAL J-QUERY™

Slide 57

Slide 57 text

curl https://api.github.com/repos/pengwynn/octokit/commits \ | jq -r '.[].author.url' | uniq -u https://api.github.com/users/patcon https://api.github.com/users/pengwynn https://api.github.com/users/sferik https://api.github.com/users/joeyw https://api.github.com/users/camelmasa https://api.github.com/users/pengwynn

Slide 58

Slide 58 text

curl https://api.github.com/repos/pengwynn/octokit/commits \ | jq -r '.[].author.url' | uniq -u https://api.github.com/users/patcon https://api.github.com/users/pengwynn https://api.github.com/users/sferik https://api.github.com/users/joeyw https://api.github.com/users/camelmasa https://api.github.com/users/pengwynn

Slide 59

Slide 59 text

curl https://api.github.com/repos/pengwynn/octokit/commits \ | jq -r '.[].author.url' | uniq -u https://api.github.com/users/patcon https://api.github.com/users/pengwynn https://api.github.com/users/sferik https://api.github.com/users/joeyw https://api.github.com/users/camelmasa https://api.github.com/users/pengwynn

Slide 60

Slide 60 text

HYPERMEDIA TYPES

Slide 61

Slide 61 text

HATEOAS A REST client enters a REST application through a simple fixed URL. * All future actions the client may take are discovered within resource representations returned from the server. * The media types used for these representations, and the link relations they may contain, are standardized. *

Slide 62

Slide 62 text

“Hypermedia Types are MIME media types that contain native hyper-linking semantics that induce application flow. For example, HTML is a hypermedia type; XML is not.” Mike Amundsen

Slide 63

Slide 63 text

“Hypermedia Types are MIME media types that contain native hyper-linking semantics that induce application flow. For example, HTML is a hypermedia type; XML is not.” Mike Amundsen

Slide 64

Slide 64 text

Neither is JSON.

Slide 65

Slide 65 text

BUT

Slide 66

Slide 66 text

BUT

Slide 67

Slide 67 text

“Hypermedia Types are MIME media types...”

Slide 68

Slide 68 text

“Hypermedia Types are MIME media types...” “...because a MIME is a terrible thing to waste.” amirite?

Slide 69

Slide 69 text

HAL

Slide 70

Slide 70 text

No content

Slide 71

Slide 71 text

HAL provides simple linking in data { "_links": { "self": { "href": "/orders" }, "next": { "href": "/orders?page=2" }, "find": { "href": "/orders{?id}", "templated": true }, "admin": [ { "href": "/admins/2", "title": "Fred" }, { "href": "/admins/5", "title": "Kate" } ] }, currentlyProcessing: 14, shippedToday: 20, "_embedded": { "orders": [{ "_links": { "self": { "href": "/orders/123" }, ... application/hal+json

Slide 72

Slide 72 text

HAL provides simple linking in data { "_links": { "self": { "href": "/orders" }, "next": { "href": "/orders?page=2" }, "find": { "href": "/orders{?id}", "templated": true }, "admin": [ { "href": "/admins/2", "title": "Fred" }, { "href": "/admins/5", "title": "Kate" } ] }, currentlyProcessing: 14, shippedToday: 20, "_embedded": { "orders": [{ "_links": { "self": { "href": "/orders/123" }, ... application/hal+json in two flavors.*

Slide 73

Slide 73 text

HAL provides simple linking in data { "_links": { "self": { "href": "/orders" }, "next": { "href": "/orders?page=2" }, "find": { "href": "/orders{?id}", "templated": true }, "admin": [ { "href": "/admins/2", "title": "Fred" }, { "href": "/admins/5", "title": "Kate" } ] }, currentlyProcessing: 14, shippedToday: 20, "_embedded": { "orders": [{ "_links": { "self": { "href": "/orders/123" }, ... application/hal+json in two flavors.* * but one is XML and has 52% more fiber.

Slide 74

Slide 74 text

HAL provides simple linking in data { "_links": { "self": { "href": "/orders" }, "next": { "href": "/orders?page=2" }, "find": { "href": "/orders{?id}", "templated": true }, "admin": [ { "href": "/admins/2", "title": "Fred" }, { "href": "/admins/5", "title": "Kate" } ] }, currentlyProcessing: 14, shippedToday: 20, "_embedded": { "orders": [{ "_links": { "self": { "href": "/orders/123" }, ... application/hal+json

Slide 75

Slide 75 text

COLLECTION+JSON

Slide 76

Slide 76 text

COLLECTION+JSON is a JSON-based read/write hypermedia-type designed to support management and querying of simple collections.

Slide 77

Slide 77 text

// sample collection object{ "collection" : { "version" : "1.0", "href" : URI, "links" : [ARRAY], "items" : [ARRAY], "queries" : [ARRAY], "template" : {OBJECT}, "error" : {OBJECT} } } COLLECTION+JSON is a JSON-based read/write hypermedia-type designed to support management and querying of simple collections.

Slide 78

Slide 78 text

// sample collection object{ "collection" : { "version" : "1.0", "href" : URI, "links" : [ARRAY], "items" : [ARRAY], "queries" : [ARRAY], "template" : {OBJECT}, "error" : {OBJECT} } } application/vnd.collection+json COLLECTION+JSON is a JSON-based read/write hypermedia-type designed to support management and querying of simple collections.

Slide 79

Slide 79 text

// sample collection object{ "collection" : { "version" : "1.0", "href" : URI, "links" : [ARRAY], "items" : [ARRAY], "queries" : [ARRAY], "template" : {OBJECT}, "error" : {OBJECT} } } application/vnd.collection+json COLLECTION+JSON is a JSON-based read/write hypermedia-type designed to support management and querying of simple collections. Read up on the format in the draft spec.

Slide 80

Slide 80 text

Why I'm down on Hypermedia Containers ...one of my main principles in adopting hypermedia is to avoid educating developers on hypermedia as much as possible. I’m in the game of providing a useful API, not a system that shows off the possibilities of hypermedia and how deeply committed I am to its theories. ADAM KEYS @therealadam

Slide 81

Slide 81 text

DETOUR

Slide 82

Slide 82 text

“I think I'll just `curl` up with a nice red and read some specs.” - Nobody Evar

Slide 83

Slide 83 text

What the SPEC? Hammer, et al. Expires November 2, 2012 [Page 10] Internet-Draft OAuth 2.0 May 2012 +--------+ +---------------+ | |--(A)------- Authorization Grant --------->| | | | | | | |<-(B)----------- Access Token -------------| | | | & Refresh Token | | | | | | | | +----------+ | | | |--(C)---- Access Token ---->| | | | | | | | | | | |<-(D)- Protected Resource --| Resource | | Authorization | | Client | | Server | | Server | | |--(E)---- Access Token ---->| | | | | | | | | | | |<-(F)- Invalid Token Error -| | | | | | +----------+ | | | | | | | |--(G)----------- Refresh Token ----------->| | | | | | | |<-(H)----------- Access Token -------------| | +--------+ & Optional Refresh Token +---------------+ Figure 2: Refreshing an Expired Access Token

Slide 84

Slide 84 text

What the SPEC? Hammer, et al. Expires November 2, 2012 [Page 10] Internet-Draft OAuth 2.0 May 2012 +--------+ +---------------+ | |--(A)------- Authorization Grant --------->| | | | | | | |<-(B)----------- Access Token -------------| | | | & Refresh Token | | | | | | | | +----------+ | | | |--(C)---- Access Token ---->| | | | | | | | | | | |<-(D)- Protected Resource --| Resource | | Authorization | | Client | | Server | | Server | | |--(E)---- Access Token ---->| | | | | | | | | | | |<-(F)- Invalid Token Error -| | | | | | +----------+ | | | | | | | |--(G)----------- Refresh Token ----------->| | | | | | | |<-(H)----------- Access Token -------------| | +--------+ & Optional Refresh Token +---------------+ Figure 2: Refreshing an Expired Access Token Page breaks. Online. In 2013.

Slide 85

Slide 85 text

Specs are a pain to write.

Slide 86

Slide 86 text

Specs are a pain to read.

Slide 87

Slide 87 text

If you've ever used an OAuth library, hug the developer.

Slide 88

Slide 88 text

URI TEMPLATES

Slide 89

Slide 89 text

curl https://api.github.com/ { current_user_url: "/user", authorizations_url: "/authorizations", emails_url: "/user/emails", emojis_url: "/emojis", events_url: "/events", following_url: "/user/following{/target}", gists_url: "/gists{/gist_id}", hub_url: "/hub", issue_search_url: "/legacy/issues/search/{owner}/{repo}/{state}/{keyword}", issues_url: "/issues", keys_url: "/user/keys", notifications_url: "/notifications", organization_repositories_url: "/orgs/{org}/repos/{?type,page,per_page,sort}", organization_url: "/orgs/{org}", public_gists_url: "/gists/public", rate_limit_url: "/rate_limit", repository_url: "/repos/{owner}/{repo}", repository_search_url: "/legacy/repos/search/{keyword}{?language,start_page}", current_user_repositories_url: "/user/repos{?type,page,per_page,sort}", ...

Slide 90

Slide 90 text

curl https://api.github.com/ { current_user_url: "/user", authorizations_url: "/authorizations", emails_url: "/user/emails", emojis_url: "/emojis", events_url: "/events", following_url: "/user/following{/target}", gists_url: "/gists{/gist_id}", hub_url: "/hub", issue_search_url: "/legacy/issues/search/{owner}/{repo}/{state}/{keyword}", issues_url: "/issues", keys_url: "/user/keys", notifications_url: "/notifications", organization_repositories_url: "/orgs/{org}/repos/{?type,page,per_page,sort}", organization_url: "/orgs/{org}", public_gists_url: "/gists/public", rate_limit_url: "/rate_limit", repository_url: "/repos/{owner}/{repo}", repository_search_url: "/legacy/repos/search/{keyword}{?language,start_page}", current_user_repositories_url: "/user/repos{?type,page,per_page,sort}", ...

Slide 91

Slide 91 text

# create the template tpl = URITemplate.new('https://api.github.com/repos/{owner}/{repo}) # Expand with given placeholder values tpl.expand :owner => "pengwynn", :repo => "octokit" => "https://api.github.com/repos/pengwynn/octokit"

Slide 92

Slide 92 text

repository_search_url: "/legacy/repos/search/{keyword}{?language,start_page}"

Slide 93

Slide 93 text

HYPERMEDIA AGENTS

Slide 94

Slide 94 text

SAWYER

Slide 95

Slide 95 text

SAWYER

Slide 96

Slide 96 text

endpoint = "http://localhost:9393/" agent = Sawyer::Agent.new(endpoint) root = agent.start root.data.rels[:users].get.data

Slide 97

Slide 97 text

module Octokit class Halogen LINK_REGEX = /_?url$/ def parse(data) links = {} inline_links = data.keys.select {|k| k.to_s[LINK_REGEX] } inline_links.each do |key| rel_name = key.to_s == 'url' ? 'self' : key.to_s.gsub(LINK_REGEX, '') links[rel_name.to_sym] = data[key] end return data, links end end end

Slide 98

Slide 98 text

FARADAY

Slide 99

Slide 99 text

No content

Slide 100

Slide 100 text

GARTNER HYPE CYCLE

Slide 101

Slide 101 text

Technology Trigger GARTNER HYPE CYCLE

Slide 102

Slide 102 text

Technology Trigger Peak of Inflated Expectations GARTNER HYPE CYCLE

Slide 103

Slide 103 text

Technology Trigger Peak of Inflated Expectations Trough of Disillusionment GARTNER HYPE CYCLE

Slide 104

Slide 104 text

Technology Trigger Peak of Inflated Expectations Trough of Disillusionment Slope of Enlightenment GARTNER HYPE CYCLE

Slide 105

Slide 105 text

Technology Trigger Peak of Inflated Expectations Trough of Disillusionment Slope of Enlightenment Plateau of Productivity GARTNER HYPE CYCLE

Slide 106

Slide 106 text

API #REALTALK

Slide 107

Slide 107 text

YOUR API IS HYPOMEDIA

Slide 108

Slide 108 text

DEMO

Slide 109

Slide 109 text

DEVELOPERS DON'T READ YOUR DOCS

Slide 110

Slide 110 text

YOU'RE NOT DOGFOODING IT

Slide 111

Slide 111 text

BUILD SOMETHING MEANINGFUL WITH YOUR API.

Slide 112

Slide 112 text

Janky BUILD SOMETHING MEANINGFUL WITH YOUR API.

Slide 113

Slide 113 text

Janky Heaven BUILD SOMETHING MEANINGFUL WITH YOUR API.

Slide 114

Slide 114 text

Janky Heaven Monitors BUILD SOMETHING MEANINGFUL WITH YOUR API.

Slide 115

Slide 115 text

Janky Team Heaven Monitors BUILD SOMETHING MEANINGFUL WITH YOUR API.

Slide 116

Slide 116 text

Janky Team Hire Heaven Monitors BUILD SOMETHING MEANINGFUL WITH YOUR API.

Slide 117

Slide 117 text

Janky Team Hire Heaven Monitors The Setup™ BUILD SOMETHING MEANINGFUL WITH YOUR API.

Slide 118

Slide 118 text

Janky Team Hire Heaven Monitors The Setup™ Graph Store BUILD SOMETHING MEANINGFUL WITH YOUR API.

Slide 119

Slide 119 text

How GitHub uses the GitHub API.

Slide 120

Slide 120 text

AuthN How GitHub uses the GitHub API.

Slide 121

Slide 121 text

AuthN AuthZ How GitHub uses the GitHub API.

Slide 122

Slide 122 text

AuthN AuthZ Merging How GitHub uses the GitHub API.

Slide 123

Slide 123 text

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

Slide 124

Slide 124 text

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

Slide 125

Slide 125 text

Do you GET me?

Slide 126

Slide 126 text

GET /me? HTTP/1.1 200 OK Server: example.com Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 200 OK

Slide 127

Slide 127 text

GET /me? HTTP/1.1 200 OK Server: example.com Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 200 OK Developer hears: :OK

Slide 128

Slide 128 text

GET /me? HTTP/1.1 200 OK Server: example.com Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 200 OK Developer hears: :OK

Slide 129

Slide 129 text

GET /me? HTTP/1.1 500 INTERNAL SERVER ERROR Server: example.com Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 500 INTERNAL SERVER ERROR

Slide 130

Slide 130 text

GET /me? HTTP/1.1 500 INTERNAL SERVER ERROR Server: example.com Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 500 INTERNAL SERVER ERROR Developer hears: :DOH

Slide 131

Slide 131 text

GET /me? HTTP/1.1 500 INTERNAL SERVER ERROR Server: example.com Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 500 INTERNAL SERVER ERROR Developer hears: :DOH

Slide 132

Slide 132 text

GET /me? HTTP/1.1 403 FORBIDDEN Server: example.com Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 403 FORBIDDEN

Slide 133

Slide 133 text

GET /me? HTTP/1.1 403 FORBIDDEN Server: example.com Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 403 FORBIDDEN Developer hears: :NOPE

Slide 134

Slide 134 text

GET /me? HTTP/1.1 302 FOUND Server: example.com Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 302 FOUND Location: https://example.com/over/there

Slide 135

Slide 135 text

GET /me? HTTP/1.1 302 FOUND Server: example.com Content-Type: application/json; charset=utf-8 Connection: keep-alive Status: 302 FOUND Location: https://example.com/over/there Developer hears: :WAT

Slide 136

Slide 136 text

/302 me

Slide 137

Slide 137 text

/302 me The requested resource resides temporarily under a different URI. Since the redirection might be altered on occasion, the client SHOULD continue to use the Request-URI for future requests. This response is only cacheable if indicated by a Cache- Control or Expires header field.

Slide 138

Slide 138 text

ETAGS ARE COOL. NOBODY USES 'EM.

Slide 139

Slide 139 text

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

Slide 140

Slide 140 text

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

Slide 141

Slide 141 text

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

Slide 142

Slide 142 text

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

Slide 143

Slide 143 text

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

Slide 144

Slide 144 text

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

Slide 145

Slide 145 text

$ 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

Slide 146

Slide 146 text

N+1 OVER HTTP IS EXPENSIVE, YO

Slide 147

Slide 147 text

Attribution Hand designed by Naomi Atkinson from The Noun Project Cereal designed by Jacob Halton from The Noun Project Evil designed by Jim Lears from The Noun Project Console designed by Austin Andrews from The Noun Project Report designed by Doug Cavendish from The Noun Project Television designed by Piero Borgo from The Noun Project Person designed by Paulo Sá Ferreira from The Noun Project Detour designed by Dmitry Baranovskiy from The Noun Project Mime designed by Jonathan C. Dietrich from The Noun Project

Slide 148

Slide 148 text

Thanks.