Presentation I gave at JPoint Meetingpoint (in a slight different version) and GotoCon Amsterdam 2012.
How to get your API or service from using the basic REST principles such as verbs and resources to a complete RESTful service that fully supports "Hypermedia as the engine of application state" (HATEOAS).
More info at www.smartjava.org
2. 2
Who am I?
~
just
some
java
guy
~
Jos Dirksen Interests Books
Architect
@
JPoint
• Java
&
Scala
Shameless
self
promotion:
• REST,
WS-‐*
• Live
in
Waalwijk
• HTML5
• SOA
Governance
in
• Married
Action,
Manning,
2012
• Daughter
(2.5
y/o)
• Snowboarding
• Open
Source
ESBs
in
• Blog
at:
• Reading
Action,
Manning,
2008
www.smartjava.org
• Cooking
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
3. 3
Disclaimer
~
you
will
encounter
opinionated
content
~
Heavily opinionated
• There are many truths
• This is mine
• I’m not a Restafarian
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
5. 5
The world before REST!
Many different ‘standards’:
RMI,
SOAP,
Corba,
DCE,
DCOM
From many different parties:
Sun,
Microsoft,
IBM,
OASIS,
OMG
Caused many problems:
• Bad
interoperability.
• Reinvent
the
wheel.
• Vendor
‘lock-‐in’.
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
6. 6
And then came REST!
“Representational State Transfer (REST) is a style of
software architecture for distributed hypermedia
systems such as the World Wide Web”
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
7. 7
REST is based on a set of constraints ~
Rest
101
~
1. Client-server 4. Uniform interface
Separate clients and servers. There is a uniform interface between
clients and servers.
2. Stateless server
Each request from a client contains all the 5. Layered System
information necessary to service the request. Must allow concepts such as load
balancers, proxies and firewalls.
3. Cacheable
Clients can cache responses, responses
6. Code-On-Demand (optional)
Client can request code from server and
must indicate if this is allowed.
execute it.
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
8. 8
Constraint 4: Uniform interface ~
Rest
101
~
A. Identification of resources:
E.g. by using an URI.
B. Manipulation of resources through representations:
A representations allows user to modify/delete resource .
C. Self-descriptive messages:
Process message based on message and meta-data.
D. Hypermedia as the engine of application state:
State transitions are defined in representations.
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
9. 9
And all was good!
Why do this? Why be RESTful?
• Scalable
• Fault-tolerant
• Recoverable
• Secure
• Loosely coupled
“Exactly what we want in the applications we are developing!”
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
10. 10
But not everybody understood…
• GET: /getAllDogs
• GET: /saveDog?name=brian&age=7
• GET: /feedDog?food=123&dog=brian
instead of:
• GET: /dogs
• PUT: /dog/brian
• POST: /dog/brian/food/123
“In your URLs – nouns are good; verbs are (usually) bad”
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
11. 11
Twitter API
~
just
saying
your
RESTful
doesn’t
make
it
so
~
Bad URLs:
• POST statuses/destroy/:id
• GET statuses/show/:id
• POST direct_messages/new
Instead of:
• DELETE status/:id
• GET status/:id
• POST direct_message or PUT direct_message/:id
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
14. 14
Level 0: The Swamp of Pox ~
nothing
to
do
with
REST
~
• One URI, one HTTP method
• XML-RPC / SOAP / POX
• Giant ‘black box’, is what eBay uses.
POST /appointmentService HTTP/1.1
[various other headers]
<appointmentRequest>
<slot doctor = "mjones" start = "1400" end = "1450"/>
<patient id = "jsmith"/>
</appointmentRequest>
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
15. 15
Level 0: eBay
~
not
an
easy
to
use
API
~
POST http://svcs.ebay.com/services/search/FindingService/v1
<findItemsByKeywordsRequest xmlns="http://www.ebay.com/marketplace/
search/v1/services">
<affiliate>
<networkId>9</networkId>
<trackingId>1234567890</trackingId>
<customId>k-man</customId>
</affiliate>
<sortOrder>EndTime</sortOrder>
<paginationInput>
<entriesPerPage>2</entriesPerPage>
</paginationInput>
<keywords>camalots</keywords>
</findItemsByKeywordsRequest>
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
16. 16
Level 1: Resources
~
lots
of
APIs
start
out
this
way
~
• Each resource has an unique URI
• Single HTTP verb (usually POST or GET)
• Verbs have no meaning, used to tunnel over HTTP
• Early versions of Flickr, del.ico.us and Amazon
POST /slots/1234 HTTP/1.1
[various other headers]
<appointmentRequest>
<patient id = "jsmith"/>
</appointmentRequest>
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
17. 17
Level 2: HTTP Verbs ~
close
but
no
sigar
~
• Many URIs, using multiple verbs
• Correct use of response codes
• Exposes state, not behavior
• Crud services, can be useful e.g Amazon S3
GET /doctors/mjones/slots?date=20100104&status=open HTTP/1.1
Host: royalhope.nhs.uk
HTTP/1.1 200 OK
<openSlotList>
<slot id = "1234” start = "1400" end = "1450"/>
<slot id = "5678” start = "1600" end = "1650"/>
</openSlotList> WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
18. 18
Level 3: Hypermedia controls ~
True
RESTful
~
• Resources are self-describing
• Hypermedia As The Engine Of Application State (HATEOAS)
• Exposes state and behavior
<appointment>
<slot id = "1234" doctor = "mjones" start = "1400"
end = "1450"/>
<patient id = "jsmith"/>
<link rel = "/linkrels/appointment/addTest"
uri = "/slots/1234/appointment/tests"/>
<link rel = "/linkrels/appointment/updateContactInfo"
uri = "/patients/jsmith/contactInfo"/>
</appointment>
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
19. 19
So, are level 0, 1 and 2 RESTful?
“What needs to be done to make the REST architectural style clear on
the notion that hypertext is a constraint? In other words, if the engine
of application state (and hence the API) is not being driven by
hypertext, then it cannot be RESTful and cannot be a REST API. Period.
Is there some broken manual somewhere that needs to be fixed?”
Roy T. Fielding
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
20. 20
Level 2 is easy, how do we do HATEOAS?~
Worst
acronym
ever!
~
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
21. 21
HATEOAS?
“The next control state of an application resides in the representation of the
first requested resource, … The application state is controlled and stored by
the user agent … anticipate changes to that state (e.g., link maps and
prefetching of representations) … The model application is therefore an engine
that moves from one state to the next by examining and choosing from among
the alternative state transitions in the current set of representations.”
Roy T. Fielding
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
23. 23
The key to HATEOAS is simple
• Hypermedia / Mime-types / Media-types :
• Describes a current state
• Compare it with a web page
• Can be seen as the contract
• Links:
• Describe the transition to the next state
• Compare it with hyperlinks
• HATEOAS makes surfing the web possible
• Jim Webber: “Hypermedia Describes Protocols” (HYDEPR)
“In each response message, include the links for the next request message”
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
26. 26
HATEOAS Part 1: Twitter Example ~
Before
using
links~
GET .../followers/ids.json?cursor=-1&screen_name=josdirksen
{
“previous_cursor”: 0,
“previous_cursor_str”: 0,
“ids”: [
12345678,
87654321,
11223344
],
“next_cursor”: 0,
“next_cursor_str”: “0”
}
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
27. 27
HATEOAS Part 1: Twitter Example ~
With
links~
GET .../followers/ids.json?cursor=-1&screen_name=josdirksen
{
“previous_cursor”: 0,
“id”: {
“name”: “John Smit”,
“id”: “12345678”
“links” : [
{ “rel”: “User info”,
“href”: “https://.../user/12345678”},
{ “rel”: “Follow user”,
“href”: “https://.../friendship/12345678”}
]
} // and add other links: tweet to, send direct message,
..// block, report for spam, add or remove from list
} WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
28. 28
HATEOAS Part 2: Media-types
WHERE:
People
know
where
to
`ind
your
resource
using
URIs.
HOW:
They
know
how
to
interact
by
following
links.
WHAT:
But
what
do
the
resources
look
like,
what
do
they
need
to
post?
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
29. 29
HATEOAS Part 2: Media-types
~
not
all
media-‐types
are
equal,
some
are
more
equal
than
others
~
• Standard formats
• Easy to use and understand.
• Clients already know how to use them
• Don’t always match with what you want to do
• XHTML and AtomPub
• Self created
• Very domain specific
• Can have rich semantics
• Client specific implementation required
• Often described using XML Schema
• or in plain text, or not at all…
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
31. 31
And that is what HATEOAS means!
• Media-types describe the resources.
• Actions are executed by following links.
• Each new response reflects a state.
• It is good to create custom media-types.
• Creates self-describing APIs.
• Clients ‘explore’ your API just as they browse the web.
“Media-types describes a domain specific
application protocol”
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
32. 32
HATEOAS Part 2: Twitter Example
~
With
links,
but
no
media-‐type
~
GET .../followers/ids.json?cursor=-1&screen_name=josdirksen
{
“previous_cursor”: 0,
“id”: {
“name”: “John Smit”,
“id”: “12345678”
“links” : [
{ “rel”: “User info”,
“href”: “https://.../user/12345678”},
{ “rel”: “Follow user”,
“href”: “https://.../friendship/12345678”}
]
}
...
} WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
33. 33
HATEOAS Part 2: Twitter Example ~
With
links
&
media-‐type
~
GET .../followers/ids.json?cursor=-1&screen_name=josdirksen
{
“previous_cursor”: 0,
“id”: {
“name”: “John Smit”,
“id”: “12345678”
“links” : [
{ “type: “application/vnd.twitter.com.user”,
“rel”: “User info”,
“href”: “https://.../user/12345678”},
{ “type”: “application/vnd.twitter.com.user.follow”,
“rel”: “Follow user”,
“href”: “https://.../friendship/12345678”}
] // and add other options: tweet to, send direct message,
// block, report for spam, add or remove from list
} // This is how you create a self-describing API.
}
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
34. 34
Case: eBay
~
API
should
guide
the
user
~
Common scenario: bidding on item
1. Add
item
to
watch
list:
keep
track
of
the
item.
2. Get
user
details:
`ind
out
more
about
the
buyer.
3. Get
user
feedback:
is
seller
trustworthy?
4. Make
a
bid:
place
a
bid
for
the
item.
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
36. 36
eBay: add to watchlist
~
API
should
tell
us
what
to
do
~
GET .../item/180881974947
{
“name” : “Monty Python and the Holy Grail white rabbit big pointy teeth”,
“id” : “180881974947”,
“start-price” : “6.50”,
“currency” : “GBP”,
...
“links” : [
{ “type: “application/vnd.ebay.item”,
“rel”: “Add item to watchlist”,
“href”: “https://.../user/12345678/watchlist/180881974947”},
{
// and a whole lot of other operations
]
}
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
37. 37
eBay: get user details
~
Follow
links
to
get
more
information
~
GET .../item/180881974947
{
“name” : “Monty Python and the Holy Grail white rabbit big pointy teeth”,
“id” : “180881974947”,
“start-price” : “6.50”,
“currency” : “GBP”,
// whole lot of other general item data
“bidder” : {
“name” : “dangermouse_rm”,
“link” : {
“type” : “application/vnd.ebay.user”,
“rel : “Get user details”,
“href : “https://.../user/314512346523”
}
}
}
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
38. 38
eBay: get user feedback
~
Depending
on
rights
we
get
different
links
~
GET .../user/314512346523
{
“name” : “dangermouse_rm”,
“location” : “united kingdom”,
// whole lot of other general user data
“feedbacks” : {
“last_month” : “7,0,0”
“last_6_month” : “19,0,0”,
“feedback” : {
“title” : “Great communication and quick delivery. +++”
“link” : {
“type” : “application/vnd.ebay.feedback”,
“rel : “Show feedback”,
“href : “https://.../user/314512346523/feedback/1234567”
}
...
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
39. 39
eBay: place bid
~
Depending
on
rights
we
get
different
links
~
GET .../item/180881974947
{
“name” : “Monty Python and the Holy Grail white rabbit big pointy teeth”,
“id” : “180881974947”,
“start-price” : “6.50”,
“currency” : “GBP”,
...
“links” : [
{ “type: “application/vnd.ebay.bid”,
“rel”: “Place bid”,
“href”: “https://.../user/12345678/bid/180881974947”},
{
// and a whole lot of other operations
]
}
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
42. 42
Three options for versioning ~
Media-‐types
~
• Media-type is versioned, directly in its name
Request:
GET /opengov/garbageschedule?location=Main%20Street HTTP/1.1
Accept: application/vnd.opengov.org.garbageschedule-v2+json
Response:
HTTP/1.1 200 OK
Content-Type: application/vnd.opengov.org.garbageschedule-v2+json
{"schedule"
"self": "schedule-2423",
"dayOfWeek": "Monday",
"oddOrEvenWeeks": "Odd"}
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
43. 43
Three options for versioning ~
Add
version
qualiGier
~
• Media-type stays the same, add a qualifier.
Request:
GET /opengov/garbageschedule?location=Main%20Street HTTP/1.1
Accept: application/vnd.opengov.org.garbageschedule+json;v=1
Response:
HTTP/1.1 200 OK
Content-Type: application/vnd.opengov.org.garbageschedule+json;v=1
{"schedule"
"self": "schedule-2423",
"dayOfWeek": "Monday",
"oddOrEvenWeeks": "Odd"}
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
44. 44
Three options for versioning ~
The
URI
is
versioned
~
• The version is added in the URI path
Request:
GET /opengov/v1/garbageschedule?location=Main%20Street HTTP/1.1
Accept: application/vnd.opengov.org.garbageschedule+json
Response:
HTTP/1.1 200 OK
Content-Type: application/vnd.opengov.org.garbageschedule+json
{"schedule"
"self": "schedule-2423",
"dayOfWeek": "Monday",
"oddOrEvenWeeks": "Odd"}
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
45. 45
Which one is the best? ~
personal
opinion
~
Matter of taste:
1. Media-‐type
approach
most
RESTful,
but
requires
work
on
client
and
server
side.
2. Quali`ier,
second
best,
easier
to
implement.
Less
media-‐
types
to
keep
track
off.
3. URI,
most
often
used.
Personally
don’t
like
it.
Can
have
two
URIs
point
to
same
resource.
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
47. 47
General idea about authentication in REST
“REST means working with the standards of the web, and the standard for
"secure" transfer on the web is SSL. Anything else is going to be kind of
funky and require extra deployment effort for clients, which will have to
have encryption libraries available.”
Highest rated answer on stackoverflow
regarding REST authentication schemes
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
48. 48
Why do we need more?
• HTTPS doesn’t fix man-in-the-middle attack
• It provides only transport level security
• Has no support for message integrity or authenticity
• REST assumes “Layered System”
• OAuth is nice (and complex) for authentication
doesn’t handle message integrity.
• REST doesn’t have a WS-Security standard
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
49. 49
HMAC based authentication ~
de
facto
standard
~
• Used by Google, Amazon AWS, Yahoo etc.
• Create a signature of the complete request, using shared secret.
• Add custom header with signature and signing user.
• Encrypt the following with this shared secret:
• URI, to avoid executing on different resource,
• Verb, indicates what we want to do with a resource,
• MD5-Header, to detect changes to the content body
• Content-type, indicates the type of resource
• Date header, to avoid replay
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN
51. 51
Parting guidelines
~
you
may
forget
everything
else
I
said
~
• Just doing URIs and Verbs doesn’t make it RESTful
• But that isn’t necessary a bad thing.
• Use “Links” to describe “HOW” your service is used.
• Describe “WHAT” is expected using media-types.
• This isn’t a complete replacement of documentation
• Don’t use WADL
• Use media-types for versioning.
• Forget what HATEOAS stands for.
WWW.JPOINT.NL
|
[email protected]
|
TWITTER:
@JOSDIRKSEN