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.

Rest in practice

1,471 views

Published on

How to design flexible and discoverable interfaces using HAL and Web API

Published in: Technology
  • Be the first to comment

Rest in practice

  1. 1. REST in practice How to design flexible and discoverable interfaces using HAL and Web API Ian Brennan, Application Architect, ezetop
  2. 2. ezetop • Market leader in international and online top up – Wholesale, retail, consumer – Integrated, online, mobile apps, responsive • 8 years building APIs – We have over 10 different APIs that allow you to top up a mobile phone • Challenge – Maintain compatibility with existing business – Implement new features – Move, divide, coalesce and transform existing services
  3. 3. Core Principles of REST based APIs HATEOAS Hypertext as the engine of application state • Navigable – Your client works the way that a browser does – Ideally, the client only constructs a single URL • Resource Driven – This is a “document driven architecture” rather than a “service oriented architecture” • HTTP-Centric – GET, PUT, POST, DELETE – Cache headers, eTags, redirects, locations
  4. 4. REST ≠ RPC (even with JSON!) REST RPC • Client follows the relationship between resources • Client uses a URI template to build a query. • Server delivers linking information between resources • Our contract is resource types, and relationship types. • Client knows the URL of each method • Client constructs query string parameter to build a query. • Client copies data between many models • Our contract is endpoint URIs, request types, and reply types.
  5. 5. Some signs you aren't RESTful Client code Builds URLs Client code constructs query strings Most of your methods use POST A proliferation of “request” and “response” classes • A proliferation of model classes • Deeply nested models • • • •
  6. 6. Why bother? • Flexible – – – – Easy to extend Easy to version Built in service locator Server side control of client side behaviour • Easy to cache – Server can control and drive caching behaviour – Standard, well understood caching model
  7. 7. Designing a REST interface • “Resource first” - Similar in nature to an ERD
  8. 8. HAL – Hypertext Application Language • JSON based – Resources – Links – Embeds http://tools.ietf.org/html/draft-kelly-json-hal
  9. 9. A Car, HAL style { "wheels": 4, "doors": 5, "_links": { "self": { "href": "http://example.com/car/1234-535" } }
  10. 10. Restrictions of HAL • There is always a single resource delivered in the body of a single request – You can use embeds to send related resources • All resources must have a “self” relationship – If it doesn’t have a URI, it isn’t a resource!
  11. 11. More useful relationships { "wheels": 4, "doors": 5, "_links": { "self": { "href": "http://example.com/car/1234-535" }, "journey-add": { "href": "http://example.com/journey?car=1234-535" }, "owner-query": { "href": "http://example.com/owner/someone" }, “change-wheel": { "href": "http://example.com/wheels/change?wheel={wheelNumber}" } }
  12. 12. Two Cars, HAL style { "count": 2, "_links": { "self": { "href": "http://example.com/car?owner=someone" } }, "_embedded": { "item": [ { "wheels": 4, "doors": 5, "_links": { "self": { "href": "http://example.com/car/1234-535" } } }, { "wheels": 4, "doors": 5, "_links": { "self": { "href": "http://example.com/car/1234-5356" } } }]}}
  13. 13. The HAL Browser • JQuery based • Browse any HAL API
  14. 14. HAL Alternatives • AtomPub/Collection+JSON – Oldest hypermedia implementation – Strong query support – Strong collection support • Siren – Invests more in describing relationships – More discoverable as a result – Strong validation semantics • So why HAL? – Simple, unobtrusive – Wide library support – Human readable
  15. 15. What’s in a link? Better living through good relationships
  16. 16. Standard Relationships http://www.iana.org/assignments/link-relations/link-relations.xhtml • • • • • • • self item edit next last profile curie List is quite arbitrary – there is no: • delete • add Mostly because these are done through verbs (but then why have edit?)
  17. 17. Custom Relationships • Non-IANA relationships should be URIs • Curies make this readable "_links": { "self": { "href": "/api/provider/Auris" }, "curies": { "href": "http://schema.ezetop.com/ild/{rel}", "name": "ild", "templated": true }, "ild:product-query": { "href": "/api/product?provider=Auris" } }
  18. 18. You reach everything by navigating relationships client .Home("/car") .Follow("veh:wheel") .Follow("veh:tyre"); Car veh:wheel veh:wheel veh:wheel Wheel Wheel Wheel veh:tyre veh:tyre veh:tyre Tyre Tyre Tyre 7 network requests! Highly cacheable
  19. 19. We can optimize using embeds... client .Home("/car") .Follow("veh:wheel") .Follow("veh:tyre"); Car veh:wheel veh:wheel veh:wheel Wheel Wheel Wheel veh:tyre veh:tyre veh:tyre Tyre Tyre Tyre 4 Network Requests Caching Moderate
  20. 20. ...as much as we like client .Home("/car") .Follow("veh:wheel") .Follow("veh:tyre"); Car veh:wheel veh:wheel veh:wheel Wheel Wheel Wheel veh:tyre veh:tyre veh:tyre Tyre Tyre Tyre 1 Network Request Caching Awful
  21. 21. Hypertext Cache Pattern client .Home("/car") .Follow("veh:wheel") .Follow("veh:tyre"); • A well written client does not care if it’s a link or an embed • Treats embeds as if they were GET requests • Optimization becomes a server side concern
  22. 22. One to many? Intermediate grouping resource Link directly • Works fine if we know there client strictly bounded are quantities .Home("/car") .Follow("veh:wheel"); • client Better for queries • Can support paging .Home("/catalog") .Follow(“shop:product-query") • Page resource open to extension .Follow(“item”); Catalog Car shop:product-query Page<Product> veh:wheel item Wheel Wheel Wheel Product Product Product
  23. 23. Linked items or embedded items? • In ezetop our framework embeds collection items within pages • We sometimes link them too Page<Product> Page<Product> item item Product Product Product Product Product Product
  24. 24. URI Templates http://www.com/car?p={pageNumber}&s={pageSize} • RFC6570 – Uri that allows value substitution – Simple values, but also lists and dictionaries – Not restricted to query strings • Implementations exist in most languages • Can be used in HAL LinkRelations – Link has "templated": true – Loosely coupled URI construction • Lightweight request types – Use sparingly!
  25. 25. Caching • HATEOS interfaces tend to be very chatty – Caching is essential • HTTP caching mechanisms – Cache-Control headers – eTags • Server controls the client cache – The server never caches content. client .Home(“http://ildserver") .Follow(“item”) .Follow(“ild:tenantproduct-by-tenant”) .Follow(“ild:account-by-consumerref”) .Follow(“ild:callernumber-query”) .Follow(“item”)
  26. 26. CacheCow.Client • Fully functional cache for .NET apps that use HttpClient – It decorates HttpClientHandler with caching semantics – Simple cache-control headers – Support for eTags also – Set it up through your IOC framework of choice • It has a pluggable store for cached resources – SQL Server, Memcached and you can build your own https://github.com/aliostad/CacheCow
  27. 27. Simple Caching Resource<Product> • Time Based – Cache-Control headers – Just like a browser cache Server 200 OK MaxAge: 10m GET Resource<Product> Cache Store Client
  28. 28. What’s an eTag? • An eTag in an HTTP response defines a version of a delivered resource • Browser automatically asks if that version still valid (If-None-Match) • Server says yes (304 Not Modified) • Client uses it’s cached version • Server does not have to re-generate resource • Built in support in all browsers
  29. 29. ETag Caching with CacheCow.Server • Content based • eTag Hash generated from resource and URI • Explicit clearing supported • Entity Tag Store Resource<Product> Entity Tag Store Product tag 200 OK 304 Not-Modified ETag: xyz – Pluggable, but standard stores exist • Challenging to configure Server GET GET eTag: xzy Resource<Product> Cache Store Client
  30. 30. Consuming REST APIs • Your client needs to be able to – – – – – Navigate relationships Parse URI templates Understand embeds Support caching (including eTags) Implement the Hypertext cache pattern • HAL is easy – navigation is hard • Is HAL suitable for a public API? – Amazon do it, among others.
  31. 31. REST in ezetop • We have started to adopt HATAEOS – August 2013 • All new services are fully RESTful • Older services are – RPC-JSON – WCF • Gradual transition to – Hypermedia API – Flat structure • Toolset – Web API 4; CacheCow; Tavis.UrlTemplates;
  32. 32. What we like       Easy to write services Flexible (not WCF!) Stateless Platform independent Standard “API First”
  33. 33. What we don’t Learning curve Too much boilerplate in server code Contract is not fully self documenting Chattiness Dealing with collections of resources
  34. 34. “I wouldn’t start from here...” • What is the correct home page for a particular API? – /api/ with all versions available? – /api/1 • What should I hard code?
  35. 35. “Is that the best way to get there?” • Choosing the best navigation path is nonobvious – Iterate early on the design • Avoid client repetition • Avoid backtracking – Where possible!
  36. 36. “Do you even know the way yourself?” • It’s tough to generate fully qualified URIs – Dev/staging/production scenarios – “Sibling” APIs • Location pattern built in, but is not free. • Strong URI-generation strategies are vital
  37. 37. Naming is hard, part 1001 • HAL is non-prescriptive on relationships – Relationship name is relatively anaemic – Siren is better here • A good naming convention can help a lot – Your relationships define your contract
  38. 38. “Why won’t you do what you’re told?” • Clients can simply ignore RESTful semantics – Parse URIs and use them to build a new query string – Rebuild links from scratch instead of accepting them from the serving application – Use string-replace instead of templated URIs • Randomly mutate URIs? • Provide client libraries?
  39. 39. “Just let me GET that for you...” • Proxy patterns are bad in REST – We can’t cache Product! • Need to avoid this anti-pattern Web Site REST client Ordering System Catalog System Product TenantProduct ProductLimit ProductCode IldVersion ProductColor Product
  40. 40. The problem with layer cakes Gateway Gateway Topup Gateway Cheap Calls Ordering API Mobile API Mobile App Payments
  41. 41. The alternative is to spread it around! Cheap Calls Payments Topup Gateway Gateway Ordering API Gateway Mobile App
  42. 42. Library Support • Libraries are available for both HAL and URI templates in most languages • Ruby, Python, Javascript, PHP, C#, Java, Scala, Objective-C, Eiffel, Clojure, Go • Quality varies • Navigation semantics will likely not be covered • Hypertext cache pattern will likely not be covered https://github.com/mikekelly/hal_specification/wiki/Libraries https://code.google.com/p/uri-templates/wiki/Implementations
  43. 43. HAL in Web API • Not a 100% natural fit – but working for us • You need to return Hal resources instead of “raw” models – Inheritance or composition both work – We use composition (with generics) • There is room for improvement – Consider alternatives in green field projects
  44. 44. Final thoughts • • • • REST is 100% pull/poll Emphasis is on flexibility Good caching strategies are vital Encourages a “flat service” structure – but that requires good security • Works well for us as an enterprise architecture – however, it relies on good client code
  45. 45. Further Research • REST – “REST in Practice” book – http://chimera.labs.oreilly.com/books/1234000001708/in dex.html • URI Templates – http://tools.ietf.org/html/rfc6570 – https://code.google.com/p/uritemplates/wiki/Implementations – https://github.com/tavis-software/UriTemplates • HAL – http://stateless.co/hal_specification.html – http://tools.ietf.org/html/draft-kelly-json-hal • CacheCow – https://github.com/aliostad/CacheCow
  46. 46. Thanks for listening! @ianbru http://ie.linkedin.com/in/ianbrennan/ http://www.slideshare.net/IanBrennan1

×