Upgrade to Pro — share decks privately, control downloads, hide ads and more …

REST in practice - PHPBenelux meetup - May 2012

REST in practice - PHPBenelux meetup - May 2012

A presentation about the "practical" side of REST. How to do stuff that seems easy when doing SOAP or XML-RPC, but becomes "hard" when you want to have a RESTful API?

Joshua Thijssen

May 02, 2012
Tweet

More Decks by Joshua Thijssen

Other Decks in Technology

Transcript

  1. 1 may 2012, Wijk bij Duurstede
    REST
    in practice?
    How to deal with

    View Slide

  2. Joshua Thijssen / Netherlands
    Freelance consultant, developer and
    trainer @ NoxLogic / Techademy
    Development in PHP, Python, Perl,
    C, Java....
    Blog: http://adayinthelifeof.nl
    Email: [email protected]
    Twitter: @jaytaph
    2

    View Slide

  3. REST
    3
    Representational State Transfer

    View Slide

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

    View Slide

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

    View Slide

  6. 4
    ➡ Quick REST recap
    ➡ Common “myths”
    ➡ Common “mistakes”
    ➡ How to do stuff
    @Todo:

    View Slide

  7. 5
    Quick REST recap

    View Slide

  8. 6
    Are you doing REST?

    View Slide

  9. Restful constraints
    7
    ➡ Client / Server
    ➡ Stateless
    ➡ Cacheable
    ➡ Layered system
    ➡ Code on demand (optional)
    ➡ Uniform interface

    View Slide

  10. Uniform interface
    8
    ➡ Identification through representations of
    resources
    ➡ Manipulation through representations
    ➡ Self-descriptive messages
    ➡ Hypermedia as the engine of application state
    (HATEOAS)

    View Slide

  11. Are you mature enough?
    9
    (according to Richardson)

    View Slide

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

    View Slide

  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

    View Slide

  14. 12
    http://martinfowler.com/articles/richardsonMaturityModel.html
    Level 1: Resources
    ➡ Entities are resources
    ➡ /user/jthijssen instead of /users
    ➡ /user/jthijssen/talks

    View Slide

  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

    View Slide

  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

    View Slide

  17. 15
    Let’s go to DisneyLand!

    View Slide

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

    View Slide

  19. 16
    Are you (still) doing REST?

    View Slide

  20. 17
    Common “myths”

    View Slide

  21. REST == HTTP
    18

    View Slide

  22. REST == CRUD
    19

    View Slide

  23. URL’s are important
    20

    View Slide

  24. REST scales
    21

    View Slide

  25. COOKIES are EVIL
    22

    View Slide

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

    View Slide

  27. 24
    Gimme moar cookies! Om nom nom!

    View Slide

  28. 25
    Application state
    vs
    Resource state

    View Slide

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

    View Slide

  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!

    View Slide

  31. ➡ Which “stage” is the user in the checkout
    process?
    ➡ Which page is the user currently browsing
    ➡ Is the user currently logged in?
    27
    Application state

    View Slide

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

    View Slide

  33. 28
    “Per client” state should be saved by the client,
    not on the server.
    It’s called Representational STATE TRANSFER

    View Slide

  34. 29
    Common “mistakes”

    View Slide

  35. 30
    PUT or POST?

    View Slide

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

    View Slide

  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

    View Slide

  38. 31
    PUT = idempotent, POST is not!

    View Slide

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

    View Slide

  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

    View Slide

  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.

    View Slide

  42. 32
    If you need to “construct” an URI, you are doing it wrong

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  46. 33
    Composite resources

    View Slide

  47. Watch out with visibility
    34



    Joshua Thijssen
    0612345678


    ...

    View Slide

  48. Watch out with visibility
    35



    Joshua Thijssen
    0612345678

    Mainstreet 1234
    1234AB
    Amsterdam
    Netherlands



    ...

    View Slide

  49. Watch out with visibility
    36
    person
    address

    View Slide

  50. Watch out with visibility
    36
    person
    address
    person address

    View Slide

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

    View Slide

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

    View Slide

  53. ➡ Degrades resource visibility since they
    contain overlapping data
    ➡ Use caching proxies! (maybe ESI???)
    ➡ Each client needs a different composite.
    37

    View Slide

  54. 38
    It sounded like a good idea at the time...

    View Slide

  55. 39

    View Slide

  56. ➡ Use HTTP (verbs) wisely
    39

    View Slide

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

    View Slide

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

    View Slide

  59. 40

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  64. ➡ 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

    View Slide

  65. ➡ Sometimes hard:
    ➡ 405 Method not allowed
    ➡ 501 Not implemented
    ➡ Who is to blame?
    41

    View Slide

  66. 42
    HTTP/1.1 200 Ok

    my-superduper-code-nobody-understands
    This action is forbidden

    Don’t return OK when it’s not:

    View Slide

  67. 43

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  71. 44
    How to do stuff

    View Slide

  72. How do I login into my API?
    45

    View Slide

  73. You don’t
    46

    View Slide

  74. 47
    Cookie
    PHPSESSID: 1234ABCD
    PHPSESSID: 1234ABCD
    LoggedIn: true
    User: 52
    IsAdmin: false
    Client Server

    View Slide

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

    View Slide

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

    View Slide

  77. 50
    Cookie:
    0xEncryptedData
    Client Server

    View Slide

  78. ➡ 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

    View Slide

  79. 52
    Querying for data

    View Slide

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

    View Slide

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

    View Slide

  82. 54
    Pagination

    View Slide

  83. 55

    View Slide

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

    View Slide

  85. 57
    /restaurants/top1000?page=5


    ...
    ...






    View Slide

  86. 58
    Applying hierarchy

    View Slide

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

    View Slide

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

    View Slide

  89. 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:

    View Slide

  90. 62
    Asynchronous updates

    View Slide

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


    My blogpost
    John Doe
    This is the content for my blog article

    Synchronous updates

    View Slide

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


    My blogpost
    John Doe
    This is the content for my blog article

    Synchronous updates
    HTTP/1.1 201 Created
    Location: /blog/20010101-myblogpost

    View Slide

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


    My blogpost
    John Doe
    This is the content for my blog article

    Asynchronous updates

    View Slide

  94. 64
    POST /blogs HTTP/1.1
    Content-type: application/vnd.myblog.article+xml ; version=1.0


    My blogpost
    John Doe
    This is the content for my blog article

    Asynchronous updates
    HTTP/1.1 202 Accepted
    Location: /queue/621252

    View Slide

  95. 65
    GET /queue/621252 HTTP/1.1
    Asynchronous updates - waiting in queue

    View Slide

  96. 65
    GET /queue/621252 HTTP/1.1
    HTTP/1.1 200 OK


    Pending
    10 minutes


    Asynchronous updates - waiting in queue

    View Slide

  97. 66
    GET /queue/621252 HTTP/1.1
    Asynchronous updates - in progress

    View Slide

  98. 66
    GET /queue/621252 HTTP/1.1
    HTTP/1.1 200 OK


    In progress
    3 minutes, 25 seconds

    Asynchronous updates - in progress

    View Slide

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

    View Slide

  100. 67
    GET /queue/621252 HTTP/1.1
    Asynchronous updates - done
    HTTP/1.1 303 See Other
    Location: /blog/20010101-myblogarticle

    View Slide

  101. 68
    Transactions

    View Slide

  102. 69
    Don’t make transactions
    through multiple resources.
    Breaks the state constraint
    (plus the rest of the the internet)

    View Slide

  103. 70
    POST /account/1234?amount=-100
    TransIDX: 55A50611FE

    View Slide

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

    View Slide

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

    View Slide

  106. 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

    View Slide

  107. 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

    View Slide

  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
    POST /commit
    TransIDX: 55A50611FE
    Nope! This is state!

    View Slide

  109. 71
    A transaction can been as a resource

    View Slide

  110. 72
    POST /transactions
    201 Created
    Location: /transactions/55A50611FE
    Create a new transaction
    Another attempt:

    View Slide

  111. 73
    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..

    View Slide

  112. 74
    POST /transactions/55A50611FE
    POST /transactions/55A50611FE/commit
    POST /transactions/55A50611FE/rollback
    POST /transactions/55A50611FE/snapshot
    POST /transactions/55A50611FE/rollback/1
    Define services:
    POST /booking

    10.000.000
    12.34.56.789, my bank
    X5252P25, Cayman Islands

    View Slide

  113. 75
    Your API is not a RDBMS.
    The internet does not need more ACID.

    View Slide

  114. 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!

    View Slide

  115. 77
    ➡ Take into account that you probably are not
    building a new twitter API.
    ➡ If you follow the REST constraints, at least
    your API can scale.

    View Slide

  116. http://farm1.static.flickr.com/73/163450213_18478d3aa6_d.jpg
    Questions?
    78

    View Slide

  117. Please rate this talk on joind.in:
    http://joind.in/6466
    Thank you
    79
    Find me on twitter: @jaytaph
    Find me for development or training: www.noxlogic.nl
    Find me on email: [email protected]
    Find me for blogs: www.adayinthelifeof.nl

    View Slide