DevoxxFR 2024 Reproducible Builds with Apache Maven
Rest in practice
1. REST in practice
How to design flexible and
discoverable interfaces using HAL
and Web API
Ian Brennan, Application Architect, ezetop
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. 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. 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. 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. 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. Designing a REST interface
• “Resource first” - Similar in nature to an ERD
8. HAL – Hypertext Application Language
• JSON based
– Resources
– Links
– Embeds
http://tools.ietf.org/html/draft-kelly-json-hal
9. A Car, HAL style
{
"wheels": 4,
"doors": 5,
"_links": {
"self": {
"href": "http://example.com/car/1234-535"
}
}
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!
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. What’s in a link?
Better living through good
relationships
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. 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. 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. ...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
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. 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. 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. 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. 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. 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. 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. 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. 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. 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. What we like
Easy to write services
Flexible (not WCF!)
Stateless
Platform independent
Standard
“API First”
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. “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. “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. “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. 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. “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. “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. The problem with layer cakes
Gateway
Gateway
Topup
Gateway
Cheap
Calls
Ordering API
Mobile API
Mobile App
Payments
41. The alternative is to spread it around!
Cheap
Calls
Payments
Topup
Gateway
Gateway
Ordering API
Gateway
Mobile App
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. 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. 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. 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
An eTag in an HTTP response defines a version of a delivered resourceClient asks if that version still valid (If-None-Match)Server says yes (304 Not Modified)Client uses it’s cached versionServer does not have to re-generate resource
The resulting interaction required a lot of URI trickery to get the right information..