Share
Embed
REST for Web Developers
Fairly introductory session on REST for a PHP user group, but contains no PHP. Lots of HTTP theory and curl examples, using GitHub's API
Lorna Mitchell
February 18, 2013
Transcript
39 slides
-
REST and HTTP On the web, we use HTTP's features
to implement REST • Verbs • Status codes • Headers -
Verbs Verbs give us CRUD Verb Collection Resource GET fetch
resources fetch one resource POST create resource PUT [create]/update resource DELETE delete resource -
Common Status Codes 200 OK 201 Created 204 No Content
304 Not Modified 400 Bad Request 404 Not Found -
Request Headers > GET / HTTP/1.1 > User-Agent: curl/7.27.0 >
Host: www.lornajane.net > Accept: */* (examples made by cURL http://curl.haxx.se/) -
Response Headers < HTTP/1.1 200 OK < Server: Apache/2.2.22 (Ubuntu)
< X-Powered-By: PHP/5.4.6-1ubuntu1.1 < X-Pingback: http://www.lornajane.net/xmlrpc.php < Vary: Accept-Encoding < Content-Type: text/html; charset=UTF-8 < Transfer-Encoding: chunked < Date: Wed, 06 Feb 2013 14:02:25 GMT < X-Varnish: 179948671 179948601 < Age: 18 < Via: 1.1 varnish < Connection: keep-alive -
Content Negotiation Agree on a format using the Accept and
Content-Type headers Header from Chrome: Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 • Server works out what format to send back • Changing Accept header changes response format -
Negotiating Other Content Details We also have: • Accept-Language •
Accept-Encoding • Accept-Charset -
GET Request Headers GET https://api.github.com/repos/lornajane/demo/issues > GET /repos/lornajane/demo/issues HTTP/1.1 >
User-Agent: curl/7.27.0 > Host: api.github.com > Accept: */* > Authorization: token 2d2d0a9b70d86b3b3ed9bac915b47a4d29fcf556f -
GET Response Headers GET https://api.github.com/repos/lornajane/demo/issues < HTTP/1.1 200 OK <
Server: GitHub.com < Date: Sun, 17 Feb 2013 20:32:24 GMT < Content-Type: application/json; charset=utf-8 < Status: 200 OK < Vary: Accept, Authorization, Cookie < Cache-Control: private, max-age=60, s-maxage=60 < Last-Modified: Sun, 17 Feb 2013 20:19:19 GMT < ETag: "d30cd8e8cd3f86e71c40334ed104f345" < X-OAuth-Scopes: gist, repo < X-Accepted-OAuth-Scopes: repo, public_repo < X-GitHub-Media-Type: github.beta < Content-Length: 1953 -
GET Response Body GET https://api.github.com/repos/lornajane/demo/issues { "url": "https://api.github.com/repos/lornajane/demo/issues/1", "comments_url": "https://api.github.com/repos/lornajane/demo/issues/1/c
"html_url": "https://github.com/lornajane/demo/issues/1", "number": 1, "title": "It's Broken", "user": { ... }, "state": "open", "comments": 0, "created_at": "2013-02-17T20:19:19Z", "updated_at": "2013-02-17T20:19:19Z", "body": "This Thing Does Not Work" } -
Hypermedia Hypermedia are hyperlinks for APIs • Clients can find
related data • Relying on following links means URLs can change -
POST Request POST https://.../repos/lornajane/demo/issues/1/comments > POST /repos/lornajane/demo/issues/1/comments HTTP/1.1 > User-Agent:
curl/7.27.0 > Host: api.github.com > Accept: */* > Content-Type: application/json > Authorization: token 2d2d0a9b70d86b3b3ed9bac915b47a4d29fcf556f > Content-Length: 37 > {"body": "some comment on the issue"} -
POST Response Header POST https://.../repos/lornajane/demo/issues/1/comments < HTTP/1.1 201 Created <
Server: GitHub.com < Date: Sun, 17 Feb 2013 21:27:15 GMT < Content-Type: application/json; charset=utf-8 < Status: 201 Created < Location: https://.../repos/lornajane/demo/issues/comments/13697012 < Content-Length: 1400 < ETag: "f8661566f14902412153409d034d464b" < Cache-Control: max-age=0, private, must-revalidate -
POST Response Body POST https://.../repos/lornajane/demo/issues/1/comments { "url": "https://.../repos/lornajane/demo/issues/comments/13697012", "issue_url": "https://.../repos/lornajane/demo/issues/11093693",
"id": 13697012, "user": { ... }, "created_at": "2013-02-17T21:27:15Z", "updated_at": "2013-02-17T21:27:15Z", "body": "some comment on the issue" } -
PUT Request PUT https://.../repos/lornajane/demo/issues/comments/13697012 > PUT /repos/lornajane/demo/issues/comments/13697012 HTTP/1.1 > User-Agent:
curl/7.27.0 > Host: api.github.com > Accept: */* > Content-Type: application/json > Authorization: token 2d2d0a9b70d86b3b3ed9bac915b47a4d29fcf556f < Content-Length: 1403 {amended json data block} -
PUT Response PUT https://.../repos/lornajane/demo/issues/comments/13697012 < HTTP/1.1 200 OK < Server:
GitHub.com < Date: Sun, 17 Feb 2013 22:09:14 GMT < Content-Type: application/json; charset=utf-8 < Connection: keep-alive < Status: 200 OK < X-OAuth-Scopes: gist, repo < X-Accepted-OAuth-Scopes: repo, public_repo < Content-Length: 1403 < ETag: "eccb456c8339572840f4c51dd8180fc7" < Cache-Control: max-age=0, private, must-revalidate -
PATCH Request PATCH https://.../repos/lornajane/demo/issues/comments/13697012 > PATCH /repos/lornajane/demo/issues/comments/13697012 HTTP/1.1 > User-Agent:
curl/7.27.0 > Host: api.github.com > Accept: */* > Content-Type: application/json > Authorization: token 2d2d0a9b70d86b3b3ed9bac915b47a4d29fcf556f < Content-Length: 39 {"body":"some other, improved comment"} -
PATCH Response PATCH https://.../repos/lornajane/demo/issues/comments/13697012 < HTTP/1.1 200 OK < Server:
GitHub.com < Date: Sun, 17 Feb 2013 22:09:14 GMT < Content-Type: application/json; charset=utf-8 < Connection: keep-alive < Status: 200 OK < X-OAuth-Scopes: gist, repo < X-Accepted-OAuth-Scopes: repo, public_repo < Content-Length: 1403 < ETag: "eccb456c8339572840f4c51dd8180fc7" < Cache-Control: max-age=0, private, must-revalidate -
DELETE Request DELETE https://.../repos/lornajane/demo/issues/comments/13697012 > DELETE /repos/lornajane/demo/issues/comments/13697012 HTTP/1.1 > User-Agent:
curl/7.27.0 > Host: api.github.com > Accept: */* > Authorization: token 2d2d0a9b70d86b3b3ed9bac915b47a4d29fcf556f -
DELETE Response DELETE https://.../repos/lornajane/demo/issues/comments/13697012 < HTTP/1.1 204 No Content <
Server: GitHub.com < Date: Sun, 17 Feb 2013 22:22:37 GMT < Connection: keep-alive < Status: 204 No Content < X-RateLimit-Limit: 5000 < X-RateLimit-Remaining: 4967 < X-OAuth-Scopes: gist, repo < X-Accepted-OAuth-Scopes: repo, public_repo < X-GitHub-Media-Type: github.beta < X-Content-Type-Options: nosniff -
Authorization Headers • Options for auth: Basic/Digest, OAuth • Use
headers, this information isn't part of a resource • Use tokens and expire tokens -
30-Second OAuth Overview OAuth handles the relationship between: • a
user • their data stored on a provder • a consumer wanting to access their data Use tokens for access, these can be revoked/expired -
Caching Headers Used exactly as we do on the web!
• Expires to say how long the client should keep the content • ETag or Last-Modified to check if something has changed • These can be used to check that a PUT updates the expected resource version -
When to use REST • For data-driven APIs • Where
REST is (or can be) understood -
Designing RESTful Services • Resources, verbs and headers • Consider
the failure case • How much data to return? How little? • Split into subresources • Allow more/less verbose representations