Hypermedia API

Preview:

DESCRIPTION

Marat Kamenschykov presentation at Rubyshift 2012.

Citation preview

What is Hypermedia API?

client code <=> API code

API:

1. namespace

2. its functions

3. their params

Web API:

1. domain (https://graph.facebook.com/)

2. addresses (/users, /groups, etc)

3. params for them (?access_token=...&...)

The main API problem:

Client-server coupling

Change in domain, URL, params →clients brake

WWW exists 20 years.

Clients don't brake

You can upgrade at any time.

Hypermedia API =Web API +

Web experience

Hypermedia API =1 URL

https://api.github.com/https://api.twilio.com/2010-04-01

Where are the URLs and params?

MIME type description

application/vnd.github-issue.text+json

application/json

application/vnd.tekpub.productions+json

application/vnd.spire-io.session+json

RFC2119:

MUST, SHALL, REQUIRED

SHOULD, RECOMMENDED

MAY, OPTIONAL

MUST NOT, SHALL NOT

SHOULD NOT, NOT RECOMMENDED

E.g.:

Response representations MUST begin with <root> element as the first element

Servers SHOULD return a response code of 204 if the HTTP DELETE request was

successful.

Document MAY contain a single filters object.

Five properties: href(REQUIRED), rel (REQUIRED), name (OPTIONAL), prompt

(OPTIONAL), and a data array (OPTIONAL)

"filters":[

{"rel":"category", "href":"...", "prompt":"",

"data":[

{"name":"category",

"value":"Microsoft"}]},

{"rel":"category", "href":"...", "prompt":"",

"data":[{"name":"category",

"value":"Ruby"}]}]

"filters":[

{"rel":"category", "href":"...", "prompt":"",

"data":[

{"name":"category",

"value":"Microsoft"}]},

{"rel":"category", "href":"...", "prompt":"",

"data":[{"name":"category",

"value":"Ruby"}]}]

Rels are described in MIME

Best MIME type is XHTML: it supports forms!

3 whales:HTTP + MIME + HATEOAS

HATEOAS: hypermedia as the engine of application state

<root>

<id>q0</id>

<link rel = "q1"

uri = "..." />

<link rel = "q2"

uri = "..." />

</entry>

<root>

<id>q1</id>

<link rel = "q0"

uri = "..." />

<link rel = "q3"

uri = "..." />

</entry>

ticket: {

assigned_to: someone,

links: [

{rel: “unassign”, url: “...”},

{rel: “close”, url: “...”}

]

}

ticket: {

assigned_to: null,

links: [

{rel: “assign”, url: “...”},

{rel: “remove”, url: “...”}

]

}

*MIME types are registered in IANA w/ public access

HTTP:

HTTP verbs:

GET

HEAD

POST

PUT

PATCH

DELETE

OPTIONS

HTTP verbs:

GET

HEAD

POST

PUT

PATCH

DELETE

OPTIONS

Status codes:

100.upto(505).almost_each do |status_code|…end

100 Continue

201 Created

202 Accepted

206 Partial Content

303 See Other

400 Bad Request

401 Unauthorized

404 Not Found

409 Conflict

412 Precondition Failed

417 Expectation Failed

100 Continue

201 Created

202 Accepted

206 Partial Content

303 See Other

400 Bad Request

401 Unauthorized

404 Not Found

409 Conflict

412 Precondition Failed

417 Expectation Failed

100 Continue

201 Created

202 Accepted

206 Partial Content

303 See Other

400 Bad Request

401 Unauthorized

404 Not Found

409 Conflict

412 Precondition Failed

417 Expectation Failed

100 Continue

201 Created

202 Accepted

206 Partial Content

303 See Other

400 Bad Request

401 Unauthorized

404 Not Found

409 Conflict

412 Precondition Failed

417 Expectation Failed

100 Continue

201 Created

202 Accepted

206 Partial Content

303 See Other

400 Bad Request

401 Unauthorized

404 Not Found

409 Conflict

412 Precondition Failed

417 Expectation Failed

100 Continue

201 Created

202 Accepted

206 Partial Content

303 See Other

400 Bad Request

401 Unauthorized

404 Not Found

409 Conflict

412 Precondition Failed

417 Expectation Failed

Request headers:

OPTIONS /payment/order/1234 HTTP 1.1 Host: starbucks.example.com

Response

200 OK Allow: GET, PUT

Request headers:

PUT /order/1234 HTTP 1.1 Host: starbucks.example.com Expect: 100-Continue

Response:

100 Continue

Request:

PUT /order/1234 HTTP 1.1 Host: starbucks.example.com {body}

Response:

200 OK

{body}

Request:

PUT /order/1234 HTTP 1.1 Host: starbucks.example.com

{body}

Response:

409 Conflict

Request:

PUT /order/1234 HTTP 1.1 Host: starbucks.example.com Expect: 100-Continue

Response:

417 Expectation Failed

HTTP Headers:Accept/typeEtagCacheAuthorizationVersionIf-Unmodified-SinceIf-Match

HTTP Headers:Accept/typeEtagCacheAuthorizationVersionIf-Unmodified-SinceIf-Match

Media types (revisited):Accept: application/xmlAccept: application/json

GET https://api.github.com/gists/1

Accept: application/json

200 OK

Content-Type: application/json; charset=utf-8

(response body)

GET https://api.github.com/gists/1

Accept: application/xml

200 OK

Content-Type: application/xml; charset=utf-8

(response body)

GET https://api.github.com/gists/1

Accept: application/xml

406 Not Acceptable

Content-Type: application/json

{

"message": "Must ACCEPT application/json: [\"application/xml\"]"

}

HTTP Headers:Accept/typeEtagCacheAuthorizationVersionIf-Unmodified-SinceIf-Match

GET https://api.github.com/gists/1

Accept: application/json

200 OK

ETag: "2259b5bea67655550030acf98bad4184"

{body}

GET https://api.github.com/gists/1

Accept: application/json

If-None-Match: "2259b5bea67655550030acf98bad4184"

304 Not Modified

HTTP Headers:Accept/typeEtagCacheAuthorizationVersionIf-Unmodified-SinceIf-Match

Authentication:Basic HTTP Authentication

(with SSL or Digesting)

HTTP Headers:Accept/typeEtagCacheAuthorizationVersionIf-Unmodified-SinceIf-Match

Accept: application/vnd.example+json

Accept: application/vnd.example+json;version=1.0

Accept: application/vnd.example-v2+json

Start point URI remains: http://api.example.com

HTTP Headers:Accept/typeEtagCacheAuthorizationVersionIf-Unmodified-SinceIf-Match

Richardson Maturity Model

1. “The Swamp of POX.” You’re using HTTP to make RPC calls. HTTP is only really used

as a tunnel.

http://api.example.com?post_id=1&user_id=2

2. Resources. Rather than making every call to a service endpoint, you have multiple

endpoints.http://api.example.com/posts/edit/1

http://api.example.com/users/show/1

3. HTTP Verbs. GET http://api.example.com/posts/1

PUT http://api.example.com/posts/1

PATCH http://api.example.com/posts/1

POST http://api.example.com/posts

DELETE http://api.example.com/posts/1

4. Hypermedia Controls. HATEOAS. You’re 100% REST compliant.

GET https://api.example.com/HTTP 1.1

Accept: application/vnd.example-v1+jsonIf-Match: “...”

Authentication: ...

200 OK{root: {entries: ...},

links: [{rel: “edit”, url: “...”}, {…}]}

No client-server coupling

1 stable URL

No dependencies on URLs and params

Client is valid forever (ideally)

Just as web browsers work

Wish you all to be at level 4

(if you want)

Thank you!

@maratkamen

marat@svitla.com

Sources:

“Architectural Styles andthe Design of Network-based Software

Architectures”http://www.ics.uci.edu/~fielding/pubs/di

ssertation/top.htm

http://blog.steveklabnik.com/posts/2012-02-27-hypermedia-api-reading-list

“Building Hypermedia APIs with HTML5 and Node”

Mike Amundsen

http://timelessrepo.com/haters-gonna-hateoas

REST is over!http://blog.steveklabnik.com/posts/2012-02-

23-rest-is-over

Questions!

Recommended