REST in practice - FrOSCon 2012

1761ecd7fe763583553dde43e62c47bd?s=47 Joshua Thijssen
August 26, 2012
6.9k

REST in practice - FrOSCon 2012

1761ecd7fe763583553dde43e62c47bd?s=128

Joshua Thijssen

August 26, 2012
Tweet

Transcript

  1. FrOSCon, Bonn - Germany 25-26 August 2012 REST in practice?

    How to deal with
  2. Joshua Thijssen / Netherlands Freelance consultant, developer and trainer @

    NoxLogic / Techademy Development in PHP, Python, Perl, C, Java.... Blog: http://adayinthelifeof.nl Email: jthijssen@noxlogic.nl Twitter: @jaytaph 2
  3. REST 3 Representational State Transfer

  4. REST 3 Representational State Transfer It’s not hard:

  5. REST 3 Representational State Transfer It’s not hard: like poker,

    or chess
  6. 4 ➡ Quick REST recap ➡ Common “myths” ➡ Common

    “mistakes” ➡ How to do stuff @Todo:
  7. 5 Quick REST recap

  8. 6 Are you doing REST?

  9. Restful constraints 7 ➡ Client / Server ➡ Stateless ➡

    Cacheable ➡ Layered system ➡ Code on demand (optional) ➡ Uniform interface
  10. Uniform interface 8 ➡ Identification through representations of resources ➡

    Manipulation through representations ➡ Self-descriptive messages ➡ Hypermedia as the engine of application state (HATEOAS)
  11. Are you mature enough? 9 (according to Richardson)

  12. 10 http://martinfowler.com/articles/richardsonMaturityModel.html

  13. 11 http://martinfowler.com/articles/richardsonMaturityModel.html Level 0: Plain Old XML ➡ HTTP is

    tunnel protocol ➡ POST to single URL (or worse: GET) ➡ SOAP / XML-RPC
  14. 12 http://martinfowler.com/articles/richardsonMaturityModel.html Level 1: Resources ➡ Entities are resources ➡

    /user/jthijssen instead of /users ➡ /user/jthijssen/talks
  15. 13 http://martinfowler.com/articles/richardsonMaturityModel.html Level 2: HTTP Verbs ➡ POST or PUT

    for creations ➡ GET for retrievals ➡ POST or PUT for updates ➡ DELETE for deletions ➡ PATCH for partial updates
  16. 14 http://martinfowler.com/articles/richardsonMaturityModel.html Level 3: Hypermedia controls ➡ HATEOAS ➡ Hypermedia

    as the engine of application state ➡ Using links to detect your next states ➡ One bookmark link to rule them all
  17. 15 Let’s go to DisneyLand!

  18. 15 Wait, wut? Let’s go to DisneyLand!

  19. 16 Are you (still) doing REST?

  20. 17 Common “myths”

  21. REST == HTTP 18

  22. REST == CRUD 19

  23. URL’s are important 20

  24. REST scales 21

  25. COOKIES are EVIL 22

  26. 23 I’ve never have eaten a cookie in my life...

  27. 24 Gimme moar cookies! Om nom nom!

  28. 25 Application state vs Resource state

  29. ➡ User has got multiple addresses ➡ Entity X/Y/Z is

    set to 42 26 Resource state
  30. ➡ User has got multiple addresses ➡ Entity X/Y/Z is

    set to 42 26 Resource state Resource state never changes through GET (or other safe) methods!
  31. ➡ Which “stage” is the user in the checkout process?

    ➡ Which page is the user currently browsing ➡ Is the user currently logged in? ➡ Depends.... 27 Application state
  32. 28 “Per client” state should be saved by the client,

    not on the server.
  33. 28 “Per client” state should be saved by the client,

    not on the server. It’s called Representational STATE TRANSFER
  34. 29 Common “mistakes”

  35. 30 PUT or POST?

  36. 30 PUT or POST? PUT when the resource URI is

    known PUT /user/jthijssen/talk/123
  37. 30 PUT or POST? PUT when the resource URI is

    known POST when it’s not (server decides) PUT /user/jthijssen/talk/123 POST /user/jthijssen/talks
  38. 31 PUT = idempotent, POST is not!

  39. 31 PUT /user/jthijssen/talk/123 PUT = idempotent, POST is not! PUT

    /user/jthijssen/talk/123 PUT /user/jthijssen/talk/123
  40. 31 PUT /user/jthijssen/talk/123 POST /user/jthijssen/talks PUT = idempotent, POST is

    not! PUT /user/jthijssen/talk/123 PUT /user/jthijssen/talk/123 POST /user/jthijssen/talks POST /user/jthijssen/talks
  41. 31 PUT /user/jthijssen/talk/123 POST /user/jthijssen/talks PUT = idempotent, POST is

    not! PUT /user/jthijssen/talk/123 PUT /user/jthijssen/talk/123 POST /user/jthijssen/talks POST /user/jthijssen/talks POST is the worst option for caching / scalability, but use it if you don’t know what to do.
  42. 32 If you need to “construct” an URI, you are

    doing it wrong
  43. 32 url = MAIN_URL + “/” + user_id + “/talks”;

    rc = HTTP.post(url, data); If you need to “construct” an URI, you are doing it wrong
  44. 32 url = data.link_rel(“talks”, user_id); rc = HTTP.post(url, data); url

    = MAIN_URL + “/” + user_id + “/talks”; rc = HTTP.post(url, data); If you need to “construct” an URI, you are doing it wrong
  45. 32 url = data.link_rel(“talks”, user_id); rc = HTTP.post(url, data); url

    = MAIN_URL + “/” + user_id + “/talks”; rc = HTTP.post(url, data); Uri can change: server, uri, protocol, port etc.. If you need to “construct” an URI, you are doing it wrong
  46. 33 Composite resources

  47. Watch out with visibility 34 <xml version=”1.0” encoding=”utf-8”> <persons> <person>

    <name>Joshua Thijssen</name> <phone type=”cell”>0612345678</phone> <link rel=”address” href=”/users/jthijssen/address”> </person> ... <persons>
  48. Watch out with visibility 35 <xml version=”1.0” encoding=”utf-8”> <persons> <person>

    <name>Joshua Thijssen</name> <phone type=”cell”>0612345678</phone> <address> <street>Mainstreet 1234</street> <postalcode>1234AB</postalcode> <city>Amsterdam</city> <country>Netherlands</country> </address> <link rel=”address” href=”/users/jthijssen/address”> </person> ... </persons>
  49. Watch out with visibility 36 person address

  50. Watch out with visibility 36 person address person address

  51. Watch out with visibility 36 person address person address address

  52. Watch out with visibility 36 person address person address address

    Duplicated cache!
  53. Watch out with visibility 36 person address person address address

    Duplicated cache!
  54. ➡ Degrades resource visibility since they contain overlapping data ➡

    Use caching proxies! (maybe ESI???) ➡ Each client needs a different composite. 37
  55. 38 It sounded like a good idea at the time...

  56. 39

  57. ➡ Use HTTP (verbs) wisely 39

  58. ➡ Use HTTP (verbs) wisely ➡ Etags / If-(not-)modified 39

  59. ➡ Use HTTP (verbs) wisely ➡ Etags / If-(not-)modified ➡

    HTTP codes 39
  60. 40

  61. ➡ HTTP 1xx : Do I got info for you!

    40
  62. ➡ HTTP 1xx : Do I got info for you!

    ➡ HTTP 2xx : We’re cool.. 40
  63. ➡ HTTP 1xx : Do I got info for you!

    ➡ HTTP 2xx : We’re cool.. ➡ HTTP 3xx : Take a look there.. 40
  64. ➡ HTTP 1xx : Do I got info for you!

    ➡ HTTP 2xx : We’re cool.. ➡ HTTP 3xx : Take a look there.. ➡ HTTP 4xx : your bad! 40
  65. ➡ HTTP 1xx : Do I got info for you!

    ➡ HTTP 2xx : We’re cool.. ➡ HTTP 3xx : Take a look there.. ➡ HTTP 4xx : your bad! ➡ HTTP 5xx : my bad! 40
  66. ➡ Sometimes hard: ➡ 405 Method not allowed ➡ 501

    Not implemented ➡ Who is to blame? (tip: blame client!) 41
  67. 42 HTTP/1.1 200 Ok <xml> <errorcode>my-superduper-code-nobody-understands<errorcode> <error>This action is forbidden</error>

    </xml> Don’t return OK when it’s not:
  68. 43

  69. ➡ Use a hypermedia format (xhtml / atom) 43

  70. ➡ Use a hypermedia format (xhtml / atom) ➡ JSON

    is NOT a hypermedia format 43
  71. ➡ Use a hypermedia format (xhtml / atom) ➡ JSON

    is NOT a hypermedia format ➡ JSON-LD http://json-ld.org/ 43
  72. ➡ Use a hypermedia format (xhtml / atom) ➡ JSON

    is NOT a hypermedia format ➡ JSON-LD http://json-ld.org/ ➡ HAL http://stateless.co/hal_specification.html 43
  73. 44 How to do stuff

  74. How do I login into my API? 45

  75. You don’t 46

  76. 47 Cookie PHPSESSID: 1234ABCD PHPSESSID: 1234ABCD LoggedIn: true User: 52

    IsAdmin: false Client Server
  77. 48 Cookie Loggedin: true User: 52 IsAdmin:false Client Server

  78. 49 Cookie Loggedin: true User: 52 IsAdmin: true Client Server

  79. 50 Cookie: 0xEncryptedData Client Server

  80. ➡ Authenticate / Authorize per request. ➡ Caching is possible,

    just don’t rely on it. ➡ If you need state, make sure it’s resource state, not session/application state. 51
  81. 52 Querying for data

  82. 53 /entities/search? what=restaurants&type=italian&postalcode=1234AB&radius=5000&sor t=rating&order=desc

  83. 53 /entities/search? what=restaurants&type=italian&postalcode=1234AB&radius=5000&sor t=rating&order=desc /restaurants/italian/top10?postalcode=1234AB&radius=5000

  84. 54 Pagination

  85. 55

  86. 56 /restaurants?page=5 /restaurants?page=635

  87. 57 /restaurants/top1000?page=5 <xml version=”1.0” encoding=”utf-8”> <restaurants> <restaurant>...</restaurant> <restaurant>...</restaurant> <link rel=”first”

    href=”/restaurants/top10?page=1”> <link rel=”self” href=”/restaurants/top10?page=5”> <link rel=”previous” href=”/restaurants/top10?page=4”> <link rel=”next” href=”/restaurants/top10?page=6”> <link rel=”last” href=”/restaurants/top10?page=25”> </restaurants>
  88. 58 Applying hierarchy

  89. 59 /directions/brussels/amsterdam Not everything implies an hierarchy:

  90. 60 /directions/brussels,amsterdam /directions/amsterdam,brussels Parameters, order does matter: /directions?from=brussels&to=amsterdam /directions?from=amsterdam&to=brussels

  91. 61 /distance/amsterdam;brussels /distance/brussels;amsterdam HTTP/1.1 303 See other Location: /distance/amsterdam;brussels Parameters,

    order does not matter: One cache system:
  92. 62 Asynchronous updates

  93. 63 POST /blogs HTTP/1.1 Content-type: application/vnd.myblog.article+xml ; version=1.0 <?xml version="1.0"

    encoding="UTF-8" ?> <article> <title>My blogpost</title> <author>John Doe</author> <content>This is the content for my blog article</content> </article> Synchronous updates
  94. 63 POST /blogs HTTP/1.1 Content-type: application/vnd.myblog.article+xml ; version=1.0 <?xml version="1.0"

    encoding="UTF-8" ?> <article> <title>My blogpost</title> <author>John Doe</author> <content>This is the content for my blog article</content> </article> Synchronous updates HTTP/1.1 201 Created Location: /blog/20010101-myblogpost
  95. 64 POST /blogs HTTP/1.1 Content-type: application/vnd.myblog.article+xml ; version=1.0 <?xml version="1.0"

    encoding="UTF-8" ?> <article> <title>My blogpost</title> <author>John Doe</author> <content>This is the content for my blog article</content> </article> Asynchronous updates
  96. 64 POST /blogs HTTP/1.1 Content-type: application/vnd.myblog.article+xml ; version=1.0 <?xml version="1.0"

    encoding="UTF-8" ?> <article> <title>My blogpost</title> <author>John Doe</author> <content>This is the content for my blog article</content> </article> Asynchronous updates HTTP/1.1 202 Accepted Location: /queue/621252
  97. 65 GET /queue/621252 HTTP/1.1 Asynchronous updates - waiting in queue

  98. 65 GET /queue/621252 HTTP/1.1 HTTP/1.1 200 OK <?xml version="1.0" encoding="UTF-8"

    ?> <queue> <status>Pending</status> <eta>10 minutes</eta> <link rel="cancel" href="/queue/621252"/> </queue> Asynchronous updates - waiting in queue
  99. 66 GET /queue/621252 HTTP/1.1 Asynchronous updates - in progress

  100. 66 GET /queue/621252 HTTP/1.1 HTTP/1.1 200 OK <?xml version="1.0" encoding="UTF-8"

    ?> <queue> <status>In progress</status> <eta>3 minutes, 25 seconds</eta> </queue> Asynchronous updates - in progress
  101. 67 GET /queue/621252 HTTP/1.1 Asynchronous updates - done

  102. 67 GET /queue/621252 HTTP/1.1 Asynchronous updates - done HTTP/1.1 303

    See Other Location: /blog/20010101-myblogarticle
  103. 68 Transactions

  104. 69 Don’t make transactions through multiple resources. Breaks the state

    constraint (plus the rest of the the internet)
  105. 70 POST /account/1234?amount=-100 TransIDX: 55A50611FE

  106. 70 POST /account/1234?amount=-100 TransIDX: 55A50611FE HTTP/1.1 202 Accepted

  107. 70 POST /account/1234?amount=-100 TransIDX: 55A50611FE HTTP/1.1 202 Accepted POST /account/4567?amount=+100

    TransIDX: 55A50611FE
  108. 70 POST /account/1234?amount=-100 TransIDX: 55A50611FE HTTP/1.1 202 Accepted POST /account/4567?amount=+100

    TransIDX: 55A50611FE HTTP/1.1 202 Accepted
  109. 70 POST /account/1234?amount=-100 TransIDX: 55A50611FE HTTP/1.1 202 Accepted POST /account/4567?amount=+100

    TransIDX: 55A50611FE HTTP/1.1 202 Accepted POST /commit TransIDX: 55A50611FE
  110. 70 POST /account/1234?amount=-100 TransIDX: 55A50611FE HTTP/1.1 202 Accepted POST /account/4567?amount=+100

    TransIDX: 55A50611FE HTTP/1.1 202 Accepted POST /commit TransIDX: 55A50611FE Nope! This is state!
  111. 71 Your API is not a RDBMS. The internet does

    not need more ACID.
  112. 72 A transaction can been as a resource

  113. 73 POST /transactions 201 Created Location: /transactions/55A50611FE Create a new

    transaction Another attempt:
  114. 74 POST /transactions/55A50611FE POST /transactions/55A50611FE/commit POST /transactions/55A50611FE/rollback POST /transactions/55A50611FE/snapshot POST

    /transactions/55A50611FE/rollback/1 But now we are back to XML-RPC or worse..
  115. 75 POST /transactions/55A50611FE POST /transactions/55A50611FE/commit POST /transactions/55A50611FE/rollback POST /transactions/55A50611FE/snapshot POST

    /transactions/55A50611FE/rollback/1 So, define services: POST /booking <xml> <amount currency=”USD”>10.000.000</amount> <from_account>12.34.56.789, my bank</from_account> <to_account>X5252P25, Cayman Islands</to_account> </xml>
  116. 76 ➡ If you do REST, don’t break the constraints.

    ➡ Be realistic about the constraints ➡ XML-RPC, HTTP-services (even SOAP) are valid for their uses. This stuff is hard!
  117. 77 ➡ Take into account that you probably are not

    building the next Twitter API. ➡ If you follow the REST constraints, at least your API can scale.
  118. http://farm1.static.flickr.com/73/163450213_18478d3aa6_d.jpg Questions? 78

  119. Thank you 79 Find me on twitter: @jaytaph Find me

    for development or training: www.noxlogic.nl Find me on email: jthijssen@noxlogic.nl Find me for blogs: www.adayinthelifeof.nl