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

Hypermedia For Y'All

0fe13386ba69a128e9fadc19ae9d96be?s=47 apotonick
December 27, 2011
150

Hypermedia For Y'All

The presentation I gave at the RubyConf Brazil 2011.

0fe13386ba69a128e9fadc19ae9d96be?s=128

apotonick

December 27, 2011
Tweet

Transcript

  1. Roar! Nick „The German“ Sutterer @apotonick Hypermedia for y'all! The

    Missing Ingredient in REST
  2. 2 Roar! 43.8 minutes... REST Representations Hypermedia Roooaaar

  3. 3 Roar! REST?

  4. 4 Roar! „architectural style for distributed hypermedia systems“ Roy Fielding's

    dissertation, chapter 5, line 1
  5. 5 Roar! require 'rest' class Application include Restful end

  6. 6 Roar! GET http://nick/state {„status“ : „sober“}

  7. Roar! Resource Unique URL http://beer/rocky Uniform Interface GET POST PUT

    ... Represen- tation
  8. Roar! „REST“ monolithic app pretty URLs GET renders models (JSON/HTML)

    POST to create and update models
  9. Roar! Mono- lithic Systems

  10. Roar! componentized app ...still pretty URLs real REST services with

    GET, PUT, POST, DELETE no HTML! embedded hypermedia REST
  11. Roar! Split it!

  12. Roar! BURP! Order!

  13. Roar! BURP! Beer shop system Using RESTful backend services and

    a separate Presentation layer !
  14. Roar! A typical REST session!

  15. Roar! GET/PUT/ http://... ------------------- <document> ------------------- <document>

  16. Roar! GET http://beers/1 name: Rocky alc : 6.0

  17. Roar! POST http://beers/ ------------------- name: Beck's alc : 5.1 Created!

    It's at http://beers/becks
  18. 18 Roar! GET: show POST: create PUT: update ... REST

    is
  19. 19 Roar! CRUD is not REST!

  20. Roar! A hypermedia- driven REST session!

  21. Roar! BURP! Order!

  22. Roar! BURP! REST Service Client

  23. 23 Roar! BURP!

  24. 24 Roar! BURP!

  25. Roar! GET http://orders/1 id: 1 created_at: August 30 to proceed:

    http://orders/1/pay to update: http://orders/1
  26. Roar! to proceed: http://orders/1/pay to update: http://orders/1 „ HATEOAS“ WTF?

  27. Roar! „HATEOAS“ - embedd actions that make sense in current

    application state
  28. Roar! {order: { id : 1 created_at: August 31 links

    : [ {rel : proceed href: http://orders/1/pay} {rel : self href: http://orders/1} ] } Hypermedia & JSON
  29. Roar! rel : proceed href: http://orders/1/pay

  30. 30 Roar! <link rel =„proceed“ href =„http://orders/1/pay“ />

  31. Roar! rel – link semantic, „meaning“ href – resource URL

  32. Roar! Creating a new order

  33. Roar! POST http://orders ------------------------ client_id: 42 id : 1 client_id:

    42 beers : [] links : [ {rel : self href: http://orders/1} {rel : beers href: http://orders/1/be ]
  34. Roar! Single entry point – the one and only URL

    we know POST http://orders ------------------------ client_id: 42
  35. Roar! id : 1 client_id: 42 beers : [] links

    : [ {rel: self href: http://orders/1} {rel: beers href: http://orders/1/beers} ] self link – pointing to current resource
  36. Roar! id : 1 client_id: 42 beers : [] links

    : [ {rel: self href: http://orders/1} {rel: beers href: http://orders/1/beers} ] beers link – items placed in order
  37. Roar! GET the new order

  38. Roar! GET http://orders/1 id : 1 client_id: 42 beers :

    [] links : [ {rel : self href: http://orders/1} {rel : beers href: http://orders/1/be ]
  39. Roar! Follow the beers link

  40. Roar! GET http://orders/1/beers beers: [] links: [ {rel : self

    href: http://orders/1/be {rel : order href: http://orders/1}
  41. Roar! Add beer to order

  42. Roar! POST http://orders/1/beers ------------------------ {name: Anchor Steam} Created! It's at

    http://orders/1/beers/anchors team Created! It's at http://orders/1/beers/anchors team
  43. Roar! Reloading the order

  44. Roar! GET http://orders/1 id : 1 client_id: 42 beers: [

    {name: Anchor Steam links: [ {rel : self href: http://orders/1/ ]} ],
  45. Roar! id : 1 client_id: 42 beers: [ {name: Anchor

    Steam links: [ {rel : self href: http://orders/1/beers/anchorsteam} ]} ], links: [ {rel: self href: http://orders/1} {rel: beers href: http://orders/1/beers} ] +
  46. Roar! id : 1 client_id: 42 beers: [ {name: Anchor

    Steam links: [ {rel : self href: http://orders/1/beers/anchorsteam} ]} ], links: [ {rel: self href: http://orders/1} {rel: beers href: http://orders/1/beers} ] +
  47. Roar! +

  48. Roar! Removing beer from order

  49. Roar! DELETE http://orders/1/beers/anchorsteam +

  50. Roar! Reloading the order

  51. Roar! GET http://orders/1 id : 1 client_id: 42 beers :

    [] links : [ {rel : self href: http://orders/1} {rel : beers href: http://orders/1/be ]
  52. Roar! GET http://orders/1 id : 1 client_id: 42 beers :

    [] links : [ {rel : self href: http://orders/1} {rel : beers href: http://orders/1/be ]
  53. 53 Roar! http://orders/ POST GET GET + DELETE ? GET

    POST
  54. 54 Roar! What we didn't do... PUT http://orders/1 DELETE http://orders/1/items

    ...
  55. 55 Roar! Code!

  56. Roar! Roar!

  57. gem 'roar'

  58. 58 Roar! class Beer include Roar::Representer::JSON property :name property :id

    link :self do beer_url(id) end Plain properties Hypermedia support yo
  59. 59 Roar! Beer.new(:id => 1, :name => "NickBrew").to_json from Roar

    {"beer":{ "id" : 1, "name" : "NickBrew", "links": [{"rel":"self","href":"http://beers/1"}]}}
  60. 60 Roar! brew = Beer.from_json '{"beer":{ "id" : 1, "name"

    : "NickBrew"}}' from Roar brew.name #=> „NickBrew“
  61. 61 Roar! class Beer include Roar::Representer::XML ... jaja brew.to_xml <beer>

    <id>1</id> <name>NickBrew</name> <link rel="self" href="http://beers/1"/> </beer>
  62. 62 Roar! class Order include Roar::Representer::JSON collection Beer

  63. 63 Roar! class Collection include Roar::Representer::JSON link :next do page_url(page)

    end end class Beers < Collection collection Beer
  64. 64 Roar! brew.new(:name => „SKOL“) brew.new(:name => „SKOL“) brew.extend Feature::HTTPVerbs

    brew.new(:name => „SKOL“) brew.extend Feature::HTTPVerbs brew.post!(„http://beers“) brew.new(:name => „SKOL“) brew.extend Feature::HTTPVerbs brew.post!(„http://beers“) puts „I'm at“ + brew.links[:self] #=> „http://beers/99“
  65. 65 Roar!

  66. 66 Roar! „REST APIs must be hypertext-driven“: http://roy.gbiv.com/untangled/2008/rest-apis-must-be- hypertext-driven REST

    in Practice – O'REILLY RESTful Web Services Cookbook – O'REILLY
  67. 67 Roar! Are you local?

  68. Roar! Thirsty? http://github.com/apotonick/roar @apotonick