+ All Categories
Home > Technology > Rest in practice

Rest in practice

Date post: 11-May-2015
Category:
Upload: ian-brennan
View: 707 times
Download: 1 times
Share this document with a friend
Description:
How to design flexible and discoverable interfaces using HAL and Web API
Popular Tags:
46
REST in practice How to design flexible and discoverable interfaces using HAL and Web API Ian Brennan, Application Architect, ezetop
Transcript
Page 1: Rest in practice

REST in practice

How to design flexible and discoverable interfaces using HAL

and Web API

Ian Brennan, Application Architect, ezetop

Page 2: Rest in practice

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

Page 3: Rest in practice

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

Page 4: Rest in practice

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.

Page 5: Rest in practice

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

Page 6: Rest in practice

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

Page 7: Rest in practice

Designing a REST interface

• “Resource first” - Similar in nature to an ERD

Page 8: Rest in practice

HAL – Hypertext Application Language

• JSON based– Resources– Links– Embeds

http://tools.ietf.org/html/draft-kelly-json-hal

Page 9: Rest in practice

A Car, HAL style

{ "wheels": 4, "doors": 5, "_links": { "self": { "href": "http://example.com/car/1234-535" }}

Page 10: Rest in practice

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!

Page 11: Rest in practice

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}" }}

Page 12: Rest in practice

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" } } }]}}

Page 13: Rest in practice

The HAL Browser

• JQuery based • Browse any

HAL API

Page 14: Rest in practice

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

Page 15: Rest in practice

What’s in a link?

Better living through good relationships

Page 16: Rest in practice

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

Page 17: Rest in practice

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" } }

Page 18: Rest in practice

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

Page 19: Rest in practice

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

Page 20: Rest in practice

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

Page 21: Rest in practice

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");

Page 22: Rest in practice

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”);

Page 23: Rest in practice

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

Page 24: Rest in practice

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}

Page 25: Rest in practice

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”)

Page 26: Rest in practice

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

Page 27: Rest in practice

Cache Store

Server

Simple Caching

• Time Based– Cache-Control headers– Just like a browser cache

Resource<Product>

Client

Resource<Product>

GET

200 OKMaxAge: 10m

Page 28: Rest in practice

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

Page 29: Rest in practice

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

Page 30: Rest in practice

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.

Page 31: Rest in practice

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;

Page 32: Rest in practice

What we like

Easy to write services Flexible (not WCF!) Stateless Platform independent Standard “API First”

Page 33: Rest in practice

What we don’t

Learning curveToo much boilerplate in server codeContract is not fully self documentingChattinessDealing with collections of resources

Page 34: Rest in practice

“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?

Page 35: Rest in practice

“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!

Page 36: Rest in practice

“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

Page 37: Rest in practice

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

Page 38: Rest in practice

“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?

Page 39: Rest in practice

“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

Page 40: Rest in practice

The problem with layer cakes

Topup Payments

Mobile App

Gateway

Mobile API

Ordering API

Cheap Calls

Gateway

Gateway

Page 41: Rest in practice

The alternative is to spread it around!

Topup

Payments

Mobile App

Gateway

Ordering API

Cheap Calls

Gateway

Gateway

Page 42: Rest in practice

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

Page 43: Rest in practice

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

Page 44: Rest in practice

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

Page 45: Rest in practice

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

Page 46: Rest in practice

Thanks for listening!

@ianbruhttp://ie.linkedin.com/in/ianbrennan/

http://www.slideshare.net/IanBrennan1


Recommended