http and your angry dog

Post on 08-May-2015

7.082 Views

Category:

Technology

3 Downloads

Preview:

Click to see full reader

DESCRIPTION

As presented at ZendCon, Confoo, LaraconEU, ZgPHP, PFCongres and Fronteers User Group. An overview of some intermediate level HTTP features and how they might be useful in practice.

TRANSCRIPT

HTTP

ZendCon 2014

& Your Angry Dog

Ross Tuck

Freerange CodemonkeyKnow-It-All

Hot-Air Balloon

Today's topic:

Dogs

HTTP & Dogs

The Agenda

Basics

Client Server

Request

Response

POST /gists HTTP/1.1

Authorization: Basic xxxxxxxx

Host: api.github.com

Content-Length: 146

{

"description": "the description for this gist",

"public": false,

"files": {

...

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": {

...

Request

2 Parts

POST /gists HTTP/1.1

Authorization: Basic xxxxxxxx

Host: api.github.com

Content-Length: 146

{

"description": "the description for this gist",

"public": false,

"files": {

...

Request

The body

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>

...

Request

The body

POST /gists HTTP/1.1

Authorization: Basic xxxxxxxx

Host: api.github.com

Content-Length: 146

{

"description": "the description for this gist",

"public": false,

"files": {

...

Request

The body

POST /gists HTTP/1.1

Authorization: Basic xxxxxxxx

Host: api.github.com

Content-Length: 146

{

"description": "the description for this gist",

"public": false,

"files": {

...

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": {

...

Request

The headers

POST /gists HTTP/1.1

Authorization: Basic xxxxxxxx

Host: api.github.com

Content-Length: 146

{

"description": "the description for this gist",

"public": false,

"files": {

...

Request

The good stuf

POST /gists HTTP/1.1

Authorization: Basic xxxxxxxx

Host: api.github.com

Content-Length: 146

{

"description": "the description for this gist",

"public": false,

"files": {

...

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": {

...

Request

GET, POST, PUT, DELETE

POST /gists HTTP/1.1

Authorization: Basic xxxxxxxx

Host: api.github.com

Content-Length: 146

{

"description": "the description for this gist",

"public": false,

"files": {

...

Request Relative URLHTTP version

POST /gists HTTP/1.1

Authorization: Basic xxxxxxxx

Host: api.github.com

Content-Length: 146

{

"description": "the description for this gist",

"public": false,

"files": {

...

Request

Key/Value pairs

POST /gists HTTP/1.1

Authorization: Basic xxxxxxxx

Host: api.github.com

Content-Length: 146

{

"description": "the description for this gist",

"public": false,

"files": {

...

Request

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",

...

ResponseStatus code

• 2xx

• 3xx

• 4xx

• 5xx

OK!

Over there!

Client screwed up!

Server screwed up!

Content Negotiation

GET /dogs/corgi HTTP/1.1

Host: api.example.com

Request

HTTP/1.1 200 OK

Date: Sun, 26 Aug 2012 18:00:43 GMT

{

"cute": true,

"big": false,

"data_dog": true

}

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>

Response

GET /dogs/corgi HTTP/1.1

Host: api.example.com

Request

GET /dogs/corgi.json HTTP/1.1

Host: api.example.com

Request

/dogs/corgi.json !== /dogs/corgi.xml

Imagine the URL as your primary key.

GET /dogs/corgi HTTP/1.1

Host: api.example.com

Request

GET /dogs/corgi?_format=json HTTP/1.1

Host: api.example.com

Request

POST /dogs/corgi?_format=json HTTP/1.1

Host: api.example.com

Request

GET /dogs/corgi HTTP/1.1

Host: api.example.com

Request

GET /dogs/corgi HTTP/1.1

Host: api.example.com

Accept: application/json

Request

More POWAH

GET /dogs/corgi HTTP/1.1

Host: api.example.com

Accept: application/json

Request

GET /dogs/corgi HTTP/1.1

Host: api.example.com

Accept: application/json, application/xml

Request

How do I choose?

GET /dogs/corgi HTTP/1.1

Host: api.example.com

Accept: application/json, application/xml

Request

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

}

Response

Nifty.

GET /dogs/corgi HTTP/1.1

Host: api.example.com

Accept: application/json, application/xml

Request

text/html, text/plain

text/html;key=value, text/plain

text/html;key=value;foo=bar, text/plain

text/html, text/plain

text/html, text/plain;q=0.5

Quality(Default 1.0)

text/html, text/plain;q=0.5, text/*;q=0.1

Wildcards

text/html, text/plain;q=0.5, */*;q=0.1

Anything at all

Accept HeadersLittle weird...

But not so scary.

text/html,application/xhtml+xml,

application/xml;q=0.9,*/*;q=0.8

Cool...

What the heck is it good for?

Accept is a “Pattern”

Accept-LanguageAccept-EncodingAccept-CharsetAccept-Ranges

Content-LanguageContent-Encoding(works differently)

Content-Range

Resource vs Representation

/dog/corgi

JSON, Dutch,Gzipped,/dog/corgi

Resource vs Representation

Best way to version your API.

Arguably.Right now.

/v1/dogs/corgi

Accept: application/vnd.dogipedia-v1+json

Accept: application/vnd.dogipedia-v2+json

Vary

Client Server

GET /dogs/corgi HTTP/1.1

Host: api.example.com

Client Server

GET /dogs/corgi HTTP/1.1

Host: api.example.com

Client ServerProxy

GET /dogs/corgi HTTP/1.1

Host: api.example.com

Client ServerProxy

GET /dogs/corgi HTTP/1.1

Host: api.example.com

Accept: application/json, text/plain

User-Species: cat

Same URL.Different output.

WTF should I return?

Client ServerProxy

GET /dogs/corgi HTTP/1.1

Host: api.example.com

Accept: application/json, text/plain

User-Species: cat

Client ServerProxy

Here's how.

Hint:Involves theVary header!

Client ServerProxy

/dogs/corgiAccept: application/json, text/plainUser-Species: cat

HTTP/1.1 200 OK

Date: Sun, 26 Aug 2012 18:00:43 GMT

Content-Type: application/json

Vary: Accept

{“json”: “omgz”}

Response

Client ServerProxy

URL and Accept?Okay, I got this.

Some time later...

Client ServerProxy

/dogs/corgiAccept: application/json, text/plainUser-Species: aardvark

Client ServerProxy

Valid cache.I has it.

Client ServerProxy

ZZ ZZZ

Z

HTTP/1.1 200 OK

Date: Sun, 26 Aug 2012 18:00:43 GMT

Content-Type: application/json

Vary: Accept

{“json”: “omgz”}

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”}

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”}

Response

Request headers.Not Response!

Bad Reputation?2 Reasons

1. Accept-Encoding -Language

2. Internet Explorer

Caching

ExpiresPragma

Cache-Control

ExpiresPragma

Cache-Control

Expires

Cache-Control

HTTP 1.0

HTTP 1.1

HTTP/1.1 200 OK

Expires: Wed, 29 Oct 2014 22:00:00 GMT

{“herp”: “derp”}

Response

HTTP/1.1 200 OK

Cache-Control: max-age=120

{“herp”: “derp”}

Response

HTTP/1.1 200 OK

Cache-Control: max-age=120

Response

Expires

Cache-Control

HTTP 1.0

HTTP 1.1

HTTP/1.1 200 OK

Cache-Control: max-age=120

{“herp”: “derp”}

Response

HTTP/1.1 200 OK

Cache-Control: max-age=120, s-maxage=120

{“herp”: “derp”}

Response

Dude, Where's my dash?

publicprivate

no-storeno-cache

no-transform

must-revalidateproxy-revalidate

Mark Nottingham's Caching Tutorialhttp://www.mnot.net/cache_docs/

Much better than me.

Conditional Requests

Conditional Requests

The Part About ETags

Conditional Requests

DELETE /ross/reputation HTTP/1.1

Host: api.joind.in

If-Talk-Quality: Crap

Request

if ($talkQuality === 'Crap') {

delete($rossReputation);

}

Not real code

Server

What kind of conditions?

If-MatchIf-None-Match

If-Modified-SinceIf-Unmodified-Since

If-Range

ETags

Datetimes

Either

Wait a second, Ross.

Audience

What the heck is an ETag?

A string.Any string.

One rule:

Represent the current state.

“14”“a381bedb5d4478053eb04be35f8798dd”

“winnie-the-pooh”

...for the current representation.

etag(“v14-json-en”) !== etag(“v14-xml-en”)

Don't cross the streams

Server

Last Modified Date sounds easier...

Audience

Wed, 15 Nov 1995 04:58:08 GMT

One second of precision

Caching With Conditionals

Use Case

GET /gists/3481910 HTTP/1.1

Host: api.github.com

Accept: */*

Request

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...",

...

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

},

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": {

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",

Response

"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"

}

GET /gists/3481910 HTTP/1.1

Host: api.github.com

Accept: */*

If-None-Match: "f4e15911542b92b44bb38186e71cc8f5"

Request

HTTP/1.1 304 Not Modified

Server: nginx/1.0.13

Date: Sun, 26 Aug 2012 18:00:43 GMT

Vary: Accept

ETag: "f4e15911542b92b44bb38186e71cc8f5"

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"

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"

Response

No giant body!

Caching.You has it.

GET /gists/3481910 HTTP/1.1

Host: api.github.com

Accept: */*

If-None-Match: "a381bedb5d4478053eb04be35f8798dd"

Request

GET /gists/3481910 HTTP/1.1

Host: api.github.com

Accept: */*

If-None-Match: "ross-is-a-poo-poo-head"

Request

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...",

Response

Recap

No ETag Old ETag Matching ETag

Full BodyFull BodyNo Body

...on supported servers.

Why?

ParsingBandwidth

Response time

Probably

.Maybe

However...

“The fastest request is one you don't make.”

- Jesus

More Fun With ETags

Optimistic Concurrency Control

“Record Versioning”

Request

GET /gists/3481910 HTTP/1.1

Host: api.github.com

Accept: */*

If-None-Match: "f4e15911542b92b44bb38186e71cc8f5"

Request

PATCH /gists/3481910 HTTP/1.1

Host: api.github.com

Accept: */*

If-None-Match: "f4e15911542b92b44bb38186e71cc8f5"

Request

PATCH /gists/3481910 HTTP/1.1

Host: api.github.com

Accept: */*

If-Match: "f4e15911542b92b44bb38186e71cc8f5"

Request

PATCH /gists/3481910 HTTP/1.1

Host: api.github.com

Accept: */*

If-Match: "f4e15911542b92b44bb38186e71cc8f5"

{ "description": "cheese om nom nom" }

Request

Response

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",

...

It works.

So what?

What if I send something...

PATCH /gists/3481910 HTTP/1.1

Host: api.github.com

Accept: */*

If-Match: "899b76047a5e68445668374c2e0faa32"

{ "description": "cheese om nom nom" }

Request

PATCH /gists/3481910 HTTP/1.1

Host: api.github.com

Accept: */*

If-Match: "stay-puft-marshmellow-dog!"

{ "description": "cheese om nom nom" }

Request

HTTP/1.1 412 Precondition Failed

Server: nginx/1.0.13

Date: Sun, 26 Aug 2012 18:00:43 GMT

Response

Response

if (“stay-puft-marshmellow-dog” == “f4e1591..”) {

patchTheRecord();

}

Server

if (“stay-puft-marshmellow-dog” == “f4e1591..”) {

patchTheRecord();

} else {

sendScary412Message();

}

Server

Your ETag is out of date.

“Two guys on the same record” problem

Scary Precondition Error pt. 2

DisclaimerNew Stuff Ahead

DELETE /gists/3481910 HTTP/1.1

Host: api.github.com

Request

HTTP/1.1 428 Precondition Required

Server: nginx/1.0.13

Date: Sun, 26 Aug 2012 18:00:43 GMT

Response

Am I operating on the latest version?

DELETE /gists/3481910 HTTP/1.1

Host: api.github.com

Request

DELETE /gists/3481910 HTTP/1.1

Host: api.github.com

If-Match: "f4e15911542b92b44bb38186e71cc8f5"

Request

HTTP/1.1 204 No Content

Server: nginx/1.0.13

Date: Sun, 26 Aug 2012 18:00:43 GMT

Response

Look before you leap.

Tooling

Epilogue: HTTP & Dogs

Content NegotiationVary

CachingPreconditions

Treat it like your framework.

Questions?

Resources

• RFC 7231–Sections 4 - 7

• http://redbot.org/

• http://mnot.net/cache_docs/

• http://charlesproxy.com/

• http://guzzlephp.org/

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

joind.in/12071

@rosstuck

Ross Tuckrosstuck.com

top related