Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Hypermedia APIs - GeekOut

1,841 views

Published on

REST is more than just JSON or XML over HTTP. In this presentation we take a closer look how to use links (hypermedia) when designing your RESTful API. Not only does this make your service discoverable and self-descriptive, but it also makes life easier for client developers as the business logic is simply checking the presence or absence of links (HATEOAS).
The presentation is based on a sample application including real business logic and not just basic collection CRUD! We also explore what mediatypes exists for hypermedia and when to use them.

  • Be the first to comment

  • Be the first to like this

Hypermedia APIs - GeekOut

  1. 1. Hypermedia APIs @jankronquist
  2. 2. Hypermedia API:s @ Jayway Rickard Öberg (~2010)! Qi4j & Streamflow! Usecases as your API! Mattias Arthursson & Karl-Johan Stenflo (~2011)! JAX-RS-HATEOAS! HATEOAS with Standard Java APIs! Mads Enevoldsen & Jan Kronquist (~2011)! Forest (CQS conventions, sensible default links, constraints...)! Gustaf Nilsson Kotte (~2012)! Adaptive HTML as your API
  3. 3. Outline Example domain! REST introduction (Richardson maturity model)! Exploring media types! html! collection+json! hal+json
  4. 4. Example domain
  5. 5. Rock - Paper - Scissors
  6. 6. Opening gambit http://www.worldrps.com/gambit-play
  7. 7. Opening gambit http://www.worldrps.com/gambit-play
  8. 8. http://rps.com The future Facebook of Rock Paper Scissors! Millions of users! Many games per user
  9. 9. Playing the game Player A Player B Server rock paper Player B: paper Player A: rock Game 123 Game 123 winner: Player B loser: Player A CREATED WAITING GAME WON GAME TIED any move other move (victory) other move (tie) T
  10. 10. Introducing REST
  11. 11. Towards REST REST architectural style! Defined by Roy Fielding ! Richardson maturity model http://martinfowler.com/articles/richardsonMaturityModel.html
  12. 12. Level 0 - Not at all RESTful Single resource, single verb! Examples:! SOAP, XML-RPC, JSON-RPC
  13. 13. Level 0 - Example POST /api --> { "method": “viewGame", "params": ["123"]} <-- { "result": { "state": "waiting"}, "error": null} POST /api --> { "method": "makeMove", "params": ["123","rock"]} <-- { "result": { "state": "won", "winner": "player1", "loser": "player2"}, "error": null}
  14. 14. Level 0 - Analysis HTTP as transport protocol! Problems! No client side caching! Tight coupling
  15. 15. Level 0 - In the wild JSON/RPC over HTTP! Why?! Simplicity! Track all user actions! If it ain’t broke, don't fix it
  16. 16. Level 1 - Resources Many resources, single verb! /api/games/123 /api/players/player1 Almost “object oriented”
  17. 17. Level 1 - Example POST /api/games/123 --> { "method": "viewGame"} <-- { "result": { "state": "waiting"}, "error": null} POST /api/games/123 --> { "method": "makeMove", "params": ["rock"]} <-- { "result": { "state": "won", "winner": "player1", "loser": "player2"}, "error": null}
  18. 18. Level 1 - Analysis Still just using HTTP as transport
  19. 19. Level 2 - Verbs Resources, verb and status codes!! GET, POST, PUT, DELETE... 200 OK, 304 Not Modified, 404 Not found… RESTish! Uniform interface
  20. 20. HTTP 101 GET - safe! POST - danger!! PUT - idempotent! ! Note! GET will not modify the resource, but other clients might! Interleaving other requests might break idempotency
  21. 21. GET /api/games/123 <-- 200 OK <-- { "state": "waiting"} POST /api/games/123 --> { "move": "rock"} <-- 200 OK <-- { "state": "won", "winner": "player1", "loser": “player2"} Level 2 - Example
  22. 22. GET /api/games/123 <-- 200 OK <-- { "state": "waiting"} POST /api/games/123 --> Content-Type: application/json --> { "move": "rock"} <-- 200 OK <-- { "state": "won", "winner": "player1", "loser": "player2"} Level 2 - Mediatype json
  23. 23. Level 2 - Mediatype form GET /api/games/123 <-- 200 OK <-- { "state": "waiting"} POST /api/games/123 --> Content-Type: application/x-www-form-urlencoded --> move=rock <-- 200 OK <-- { "state": "won", "winner": "player1", "loser": "player2"} $ curl -d move=rock http://rps.com/api/games/123
  24. 24. Level 2 - In the wild Verbs: GET, DELETE, PUT! Resources: buckets, objects, acls, policies…! Why?! CRUD operations! GET allows caching
  25. 25. Level 2 - Analysis Using HTTP, not fighting it! Problems! Client must construct URLs! Client must contain business rules
  26. 26. GET /api/games <-- 200 OK <-- { "totalCount": 23, "offset": 0, "pageSize": 10, "items": [{"id": "111", "players": ["jan", "cecilia"]}, {"id": "222", "players": ["jan", "mike"]}, {"id": "333", "players": ["cecilia", "mike"]}, ...]} Level 2 - Constructing URLs GET /api/games?offset=10 GET /api/games?page=2 How to navigate to page 2?
  27. 27. GET /api/games <-- 200 OK <-- { "totalCount": 23, "offset": 0, "pageSize": 10, "items": [{"id": "111", "players": ["jan", "cecilia"]}, {"id": "222", "players": ["jan", "mike"]}, {"id": "333", "players": ["cecilia", "mike"]}, ...]} Level 2 - Constructing URLs GET /api/games/{game.id} Navigating to game
  28. 28. Level 2 - Business logic GET /api/games/123 <-- 200 OK <-- { "state": "waiting", "players": ["ply1", "ply2"], "moves": { "ply1" : true} } Should the client display the move selector?
  29. 29. Level 2 - Business logic solved? GET /api/games/123 <-- 200 OK <-- { "state": "waiting", "players": ["ply1", "ply2"], "moves": { "ply1" : true}, "shouldMove": true }
  30. 30. Level 3 - Hypermedia Controls Links & forms! REST as defined by Roy Fielding Hypermedia is defined by the presence of application control information embedded within, ! or as a layer above, the presentation of information The simultaneous presentation of information and controls such that the information becomes the affordance through which the user obtains choices and selects actions.
  31. 31. GET /api/games <-- 200 OK <-- { "totalCount": 23, "offset": 0, "pageSize": 10, "next": "/api/games?offset=10", "items": [{"href": "/api/games/111", "players": ["jan", "cecilia"]}, {"href": "/api/games/222", "players": ["jan", "mike"]}, {"href": "/api/games/333" "players": ["cecilia", "mike"]}, ...]} Level 3 - Example (links)
  32. 32. Level 3 - Example (form) <html> <body> <ol id="players"> <li>Jan</li> <li>Cecilia</li> </ol> <form action="/api/games/111" method="POST"> <select name="move"> <option value="rock">Rock</option> <option value="paper">Paper</option> <option value="scissors">Scissors</option> </select> <input type="submit"/> </form> </body> </html>
  33. 33. Level 3 - Opportunity: Extra moves <select name="move"> <option value="rock">Rock</option> <option value="paper">Paper</option> <option value="scissors">Scissors</option> <option value="lizard">Lizard</option> <option value="spock">Spock</option> </select>
  34. 34. Level 3 - Changing the rules For one of the players: Flip a coin! head - he must play rock! tail - he can play whatever he wants! ! How can the other player take advantage of this? http://blog.gtorangebuilder.com/2014/04/gto-brain-teaser-1-exploitation-and.html <select name="move"> <option value="rock">Rock</option> </select>
  35. 35. Level 3 - In the wild
  36. 36. Media types & other tools
  37. 37. Media types Format! application/json, text/xml, text/plain, text/csv! Domain specific! text/vcard, text/calendar, application/calendar+json! Hypermedia! text/html, application/xhtml+xml! application/vnd.collection+json, application/vnd.hal+json! application/vnd.siren+json, application/vnd.amundsen-uber+json
  38. 38. GET /api/games <-- 200 OK <-- Content-Type: application/json <-- { "totalCount": 23, "offset": 0, "pageSize": 10, "next": "/api/games?offset=10", ... } json
  39. 39. xhtml GET /api/games <-- 200 OK <-- Content-Type: application/xhtml+xml <-- <html> <body> <a href="/api/games?offset=10">Next</a> <div id="totalCount">23</div> <ol id="games"> <li>...</li> <li>...</li> </ol> </body> </html>
  40. 40. collection+json CRUD for collections of objects! Parts of the document:! items! links! queries! templates! errors
  41. 41. GET /api/games <-- 200 OK <-- Content-Type: application/vnd.collection+json <-- { "collection": { "version" : "1.0", "href" : "http://rps.com/api/games", "links" : [ {"rel" : "next", "href" : "/api/games?offset=10"} ], "items" : [ { ... }, { ... } ] } } collection+json
  42. 42. Anatomy of a Link target url (href)! human readable string (title)! semantic information (rel)! returned media types (type)! ! http method (method)! secondary key (name)! support media types for requests (accept) RFC 5988
  43. 43. Standard rels item! collection! next! edit! enclosure! latest-version! self http://www.iana.org/assignments/link-relations/link-relations.xml
  44. 44. Custom rels Register with IANA :-)! Just make up your own :-)! move! URI! http://rps.com/rels/move! CURIE! rps:move! http://rps.com/rels/{rel}
  45. 45. Forms / templates More than links! Allow user input! May provide! Default values! Data types! Possible values
  46. 46. html form <html> <body> <ol id="players"> <li>Jan</li> <li>Cecilia</li> </ol> <form action="/api/games/111" method=“POST" name="move"> <select name="move"> <option value="rock">Rock</option> <option value="paper">Paper</option> <option value="scissors">Scissors</option> </select> <input type="submit"/> </form> </body> </html>
  47. 47. GET /api/games/111 <-- 200 OK <-- Content-Type: application/vnd.collection+json <-- { "collection": { "version" : "1.0", "href" : "http://rps.com/api/games/111", "template" : { "data" : [{ "name" : "move", "value" : "", "prompt" : "Your move" }] } } } collection+json template for writes
  48. 48. Forced resource structure Collection of games /api/games/ Game 111 /api/games/111 Collection of moves for game 111 /api/games/111/moves Player 1 move for game 111 /api/games/111/moves/ply1 item rps:moves item
  49. 49. GET /api/games/111 <-- 200 OK <-- Content-Type: application/vnd.collection+json <-- { "collection": { "version" : "1.0", "href" : "http://rps.com/api/games/111", "links" : [ {"rel" : "rps:moves", "href" : "/api/games/111/moves"} ], ... } } The game links to moves
  50. 50. GET /api/games/111/moves <-- 200 OK <-- Content-Type: application/vnd.collection+json <-- { "collection": { "version" : "1.0", "href" : "http://rps.com/api/games/111/moves", "template" : { "data" : { "name" : "move", "value" : "", "prompt" : "Your move" } } } } moves collection contain template
  51. 51. URI templates Constructing paths
 
 Form-style! Making a move
 
 Creating a new game RFC 6570 "http://rps.com/api/games/111{?move}" "http://rps.com/api/games/{gameId}" "http://rps.com/api/games{?player1,player2}"
  52. 52. application/vnd.hal+json Minimalistic (plain old json)! "_links" with mandatory rels! "_embedded" (recursive!)
  53. 53. GET http://rps.com/api/games/123 <-- { ! ! ! ! ! ! ! ! ! ! ! ! ! ! "createdAt" : "2014-05-22T16:24:01", "state" : "waiting" } hal+json
  54. 54. GET http://rps.com/api/games/123 <-- { ! ! ! ! ! ! ! ! "_links": { "rps:move": { "href": "http://rps.com/api/games/123{?move}", "templated": true } } "createdAt" : "2014-05-22T16:24:01", "state" : "waiting" } hal+json
  55. 55. GET http://rps.com/api/games/123 <-- { "_embedded": { "rps:player" : [{ "_links": { "self": {"href" : "http://rps.com/api/players/111"}, "name": "Jan" }, { "_links": { "self": {"href" : "http://rps.com/api/players/222"}, "name": "Cecilia" }] }, "_links": { "rps:move": { "href": "http://rps.com/api/games/123{?move}", "templated": true } } "createdAt" : "2014-05-22T16:24:01", "state" : "waiting" } hal+json
  56. 56. Application state, not objects GET http://rps.com/api/players/111/games/123 <-- { "_links": { "rps:game": {"href" : "http://rps.com/api/games/123"}, "rps:move": { "href": "http://rps.com/api/games/123{?move}", "templated": true } } }
  57. 57. GET http://rps.com/api/players/111/games/123 <-- { "_embedded": { "rps:game" : [{ "_links": { "self": {"href" : "http://rps.com/api/games/123"}, "createdAt" : "2014-05-22T16:24:01", "state" : "waiting" }] }, "_links": { "rps:move": { "href": "http://rps.com/api/games/123{?move}", "templated": true } } } Application state, not objects
  58. 58. Summary Hypermedia simplifies client development! No constructing of URLs! Opportunities for less business logic! Pick a mediatype with reasonable semantics! Consider form-encoded when POSTing! Some useful tools! CURIE, URITemplates

×