Rest in practice
-
Upload
ian-brennan -
Category
Technology
-
view
710 -
download
1
description
Transcript of Rest in practice
REST in practice
How to design flexible and discoverable interfaces using HAL
and Web API
Ian Brennan, Application Architect, ezetop
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
Core Principles of REST based APIs
• 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
HATEOASHypertext as the engine of application state
REST ≠ RPC (even with JSON!)
REST• 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.
RPC• 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.
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
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
Designing a REST interface
• “Resource first” - Similar in nature to an ERD
HAL – Hypertext Application Language
• JSON based– Resources– Links– Embeds
http://tools.ietf.org/html/draft-kelly-json-hal
A Car, HAL style
{ "wheels": 4, "doors": 5, "_links": { "self": { "href": "http://example.com/car/1234-535" }}
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!
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}" }}
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" } } }]}}
The HAL Browser
• JQuery based • Browse any
HAL API
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
What’s in a link?
Better living through good relationships
Standard Relationships
• 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?)
http://www.iana.org/assignments/link-relations/link-relations.xhtml
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" } }
You reach everything by navigating relationships
Car
WheelWheel Wheel
TyreTyreTyre
veh:wheelveh:wheelveh:wheel
veh:tyre veh:tyreveh:tyre
client .Home("/car").Follow("veh:wheel").Follow("veh:tyre");
7 network requests!
Highly cacheable
Car
We can optimize using embeds...
WheelWheel Wheel
TyreTyreTyre
veh:wheelveh:wheelveh:wheel
veh:tyre veh:tyreveh:tyre
client .Home("/car").Follow("veh:wheel").Follow("veh:tyre");
Caching - Moderate
4 Network Requests
Car
...as much as we like
WheelWheel Wheel
TyreTyreTyre
veh:wheelveh:wheelveh:wheel
veh:tyre veh:tyreveh:tyre
client .Home("/car").Follow("veh:wheel").Follow("veh:tyre");
Caching - Awful
1 Network Request
Hypertext Cache Pattern
• 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
client .Home("/car").Follow("veh:wheel").Follow("veh:tyre");
One to many?
Link directly• Works fine if we know there are
strictly bounded quantities
Intermediate grouping resource
• Better for queries• Can support paging
• Page resource open to extension
Car
WheelWheel Wheel
veh:wheelPage<Product>
ProductProduct Product
item
Catalog
shop:product-query
client .Home("/car").Follow("veh:wheel");
client .Home("/catalog").Follow(“shop:product-query").Follow(“item”);
Linked items or embedded items?
• In ezetop our framework embeds collection items within pages
• We sometimes link them too
Page<Product>
Product Product Product
item
Page<Product>
ProductProduct Product
item
URI Templates
• 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!
http://www.com/car?p={pageNumber}&s={pageSize}
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”)
client .Home(“http://ildserver") .Follow(“item”) .Follow(“ild:tenantproduct-by-tenant”) .Follow(“ild:account-by-consumerref”) .Follow(“ild:callernumber-query”) .Follow(“item”)
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
Cache Store
Server
Simple Caching
• Time Based– Cache-Control headers– Just like a browser cache
Resource<Product>
Client
Resource<Product>
GET
200 OKMaxAge: 10m
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
GETeTag: xzy
Cache Store
Server
ETag Caching with CacheCow.Server
• Content based• eTag Hash generated
from resource and URI• Explicit clearing
supported• Entity Tag Store
– Pluggable, but standard stores exist
• Challenging to configure
Resource<Product>
Client
Resource<Product>
Entity Tag Store
Product tag
GET
200 OKETag: xyz
304 Not-Modified
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.
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;
What we like
Easy to write services Flexible (not WCF!) Stateless Platform independent Standard “API First”
What we don’t
Learning curveToo much boilerplate in server codeContract is not fully self documentingChattinessDealing with collections of resources
“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?
“Is that the best way to get there?”
• Choosing the best navigation path is non-obvious– Iterate early on the design
• Avoid client repetition• Avoid backtracking
– Where possible!
“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
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
“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?
“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 Ordering System
Catalog SystemREST client IldVersion
TenantProduct
Product
Product
ProductCode
ProductLimit
ProductColor
The problem with layer cakes
Topup Payments
Mobile App
Gateway
Mobile API
Ordering API
Cheap Calls
Gateway
Gateway
The alternative is to spread it around!
Topup
Payments
Mobile App
Gateway
Ordering API
Cheap Calls
Gateway
Gateway
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/Librarieshttps://code.google.com/p/uri-templates/wiki/Implementations
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
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
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/uri-templates/wiki/Implement
ations– 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
Thanks for listening!
@ianbruhttp://ie.linkedin.com/in/ianbrennan/
http://www.slideshare.net/IanBrennan1