five inconvenient truths about rest
TRANSCRIPT
FIVE INCONVENIENT TRUTHS ABOUT RESTFilip van Laenen
1https://www.flickr.com/photos/grantmac/4192158869
Who Am I?
2
● 18 years of experience as a developer/architect
● Been involved in a number of REST projects
– Client/consumer
– Server/producer
● Things I wish I knew a couple of years ago…
http://www.slideshare.net/filipvanlaenen/
REST – Representational state transfer
3
From Wikipedia:
“Representational State Transfer (REST) is a software architecture style for building scalable web services.
REST gives a coordinated set of constraints to the design of components in a distributed hypermedia system that can lead to a higher performing and more maintainable architecture.”
REST – Representational state transfer
4
From Wikipedia:
“RESTful systems typically, but not always, communicate over the Hypertext Transfer Protocol with the same HTTP verbs (GET, POST, PUT, DELETE, etc.) which web browsers use to retrieve web pages and to send data to remote servers.
REST interfaces usually involve collections of resources with identifiers, for example /people/paul, which can be operated upon using standard verbs, such as DELETE /people/paul.”
5http://martinfowler.com/articles/richardsonMaturityModel.html
Richardson Maturity Model
So, what's wrong with REST?
6
Ever Heared a REST-Discussion about “State”?
7
Ever Heared a REST-Discussion about “State”?
8
From Wikipedia:
“The client–server communication is constrained by no client context being stored on the server between requests.”
INCONVENIENT TRUTH #1:
GET calls are never nullipotent
9https://www.flickr.com/photos/grantmac/4192158869
10http://martinfowler.com/articles/richardsonMaturityModel.html
Richardson Maturity Model
What does «nullipotent» mean?
11
From Wikipedia:
“The GET method is a safe method (or nullipotent), meaning that calling it produces no side-effects.”
What does «nullipotent» mean?
12
From Wikipedia:
“The GET method is a safe method (or nullipotent), meaning that calling it produces no side-effects.”
13
Tomcat Access Log
Wanted Side-effects
● Access log from a REST resource
● Access control
– Three strikes and you're out
● One-time downloads
– Think “Snapchat”
14
GET Methods with Side-effects Are OK
15
…if the side-effects are:
● General good practices
● Part of the domain
GET Methods with Side-effects Are OK
16
…if the side-effects are:
● General good practices
● Part of the domain
In other words:
● Unobservable
● Expected
INCONVENIENT TRUTH #2:
HTTP Verbs ≠ “REST Verbs”
17https://www.flickr.com/photos/grantmac/4192158869
18http://martinfowler.com/articles/richardsonMaturityModel.html
Richardson Maturity Model
19https://en.wikipedia.org/wiki/Representational_state_transfer
HTTP Verbs
20https://en.wikipedia.org/wiki/Representational_state_transfer
HTTP Verbs
HTTP/1.1 Spec about POST and PUT
21
The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line.
The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.
HTTP/1.1 Spec about POST and PUT
22
The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line.
The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.
HTTP/1.1 Spec about POST and PUT
23
The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line.
The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.
HTTP/1.1 Spec about POST and PUT
24
The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line.
The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.
25https://en.wikipedia.org/wiki/Representational_state_transfer
HTTP Verbs
INCONVENIENT TRUTH #3:
HTTP Response Codes ≠ “REST Response Codes”
26https://www.flickr.com/photos/grantmac/4192158869
27http://martinfowler.com/articles/richardsonMaturityModel.html
Richardson Maturity Model
Martin Fowler on HATEOAS
28
“The key elements that are supported by the existence of the web are the strong separation between safe (eg GET) and non-safe operations, together with using status codes to help communicate the kinds of errors you run into.”
http://martinfowler.com/articles/richardsonMaturityModel.html
29http://www.restapitutorial.com/httpstatuscodes.html
30http://www.restapitutorial.com/httpstatuscodes.html
31http://www.restapitutorial.com/httpstatuscodes.html
What If Something Else Is Wrong?
32
Semantical errors, but syntactically correct:
● References to resources that don't exist
● Illegal values
● Invalid combination of choices
● Anything else that doesn't make sense in your domain
33http://www.restapitutorial.com/httpstatuscodes.html
422 Unprocessable Entity
34
From IETF RFC 4918:
“The 422 (Unprocessable Entity) status code means the server understands the content type of the request entity (hence a 415 (Unsupported Media Type) status code is inappropriate), and the syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions.
For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.”
https://tools.ietf.org/html/rfc4918#section-11.2
35http://www.restapitutorial.com/httpstatuscodes.html
INCONVENIENT TRUTH #4:
HATEOAS YAGNI⇒
36https://www.flickr.com/photos/grantmac/4192158869
37Fra: http://martinfowler.com/articles/richardsonMaturityModel.html
Richardson Maturity Model
HATEOAS
38
Hypermedia as the engine of application state
From Wikipedia:
“Clients make state transitions only through actions that are dynamically identified within hypermedia by the server.
Except for simple fixed entry points to the application, a client does not assume that any particular action is available for any particular resources beyond those described in representations previously received from the server.”
Example Message
39
<Hire id="h101442"> <CcuId>141705</CcuId> <EnclosingHireIds> <EnclosingHireId distance="1">a1</EnclosingHireId> </EnclosingHireIds> <OrgNo>123456789</OrgNo> <GlnLocation>1234567890123</GlnLocation> <StartDate>2013-10-09</StartDate> <EndDate>2013-11-08</EndDate> <Link href="/ccus/141705/hires/a1/hires/h101442" method="get" rel="self"/> <Link href="/ccus/141705" method="get" rel="Ccu"/> <Link href="/ccus/141705/hires/a1" method="get" rel="EnclosingHire"/></Hire>
Example Message
40
<Hire id="h101442"> <CcuId>141705</CcuId> <EnclosingHireIds> <EnclosingHireId distance="1">a1</EnclosingHireId> </EnclosingHireIds> <OrgNo>123456789</OrgNo> <GlnLocation>1234567890123</GlnLocation> <StartDate>2013-10-09</StartDate> <EndDate>2013-11-08</EndDate> <Link href="/ccus/141705/hires/a1/hires/h101442" method="get" rel="self"/> <Link href="/ccus/141705" method="get" rel="Ccu"/> <Link href="/ccus/141705/hires/a1" method="get" rel="EnclosingHire"/></Hire>
Example Message
41
<Hire id="h101442"> <CcuId>141705</CcuId> <EnclosingHireIds> <EnclosingHireId distance="1">a1</EnclosingHireId> </EnclosingHireIds> <OrgNo>123456789</OrgNo> <GlnLocation>1234567890123</GlnLocation> <StartDate>2013-10-09</StartDate> <EndDate>2013-11-08</EndDate> <Link href="/ccus/141705/hires/a1/hires/h101442" method="get" rel="self"/> <Link href="/ccus/141705" method="get" rel="Ccu"/> <Link href="/ccus/141705/hires/a1" method="get" rel="EnclosingHire"/></Hire>
199 out of 477 bytes(42%)
Example Message using Full HATEOAS
42
<Hire id="h101442"> <CcuId>141705</CcuId> <EnclosingHireIds> <EnclosingHireId distance="1">a1</EnclosingHireId> </EnclosingHireIds> <OrgNo>123456789</OrgNo> <GlnLocation>1234567890123</GlnLocation> <StartDate>2013-10-09</StartDate> <EndDate>2013-11-08</EndDate> <Link href="/ccus/141705/hires/a1/hires/h101442" method="get" rel="self"/> <Link href="/ccus/141705" method="get" rel="Ccu"/> <Link href="/ccus/141705/hires/a1" method="get" rel="EnclosingHire"/> <Link href="/organizations/123456789" method="get" rel="Organization"/> <Link href="/organizations/123456789/locations/1234567890123" method="get" rel="Location"/> <Link href="/ccus/141705/hires/a1/hires/h101442/documents" method="post" rel="Documents"/> <Link href="/ccus/141705/hires/a1/hires/h101442" method="put" rel="update"/> <Link href="/ccus/141705/hires/a1/hires/h101442/hires" method="post" rel="addHire"/></Hire>
620 out of 899 bytes(69%)
Martin Fowler on HATEOAS
43
“One obvious benefit of hypermedia controls is that it allows the server to change its URI scheme without breaking clients. As long as clients look up the ‘addTest’ link URI then the server team can juggle all URIs other than the initial entry points.”
http://martinfowler.com/articles/richardsonMaturityModel.html
Martin Fowler on HATEOAS
44
“A further benefit is that it helps client developers explore the protocol. The links give client developers a hint as to what may be possible next. It doesn't give all the information: both the “latest” and “cancel” controls point to the same URI – they need to figure out that one is a GET and the other a DELETE. But at least it gives them a starting point as to what to think about for more information and to look for a similar URI in the protocol documentation.”
http://martinfowler.com/articles/richardsonMaturityModel.html
Cost/Benefit of HATEOAS
What will change most often?● Behavior● Content● URIs
What's hard to refactor?● Behavior● Content● URIs
45
Example Message
46
<Hire id="h101442"> <CcuId>141705</CcuId> <EnclosingHireIds> <EnclosingHireId distance="1">b2</EnclosingHireId> <EnclosingHireId distance="2">a1</EnclosingHireId> </EnclosingHireIds> <OrgNo>123456789</OrgNo> <GlnLocation>1234567890123</GlnLocation> <StartDate>2013-10-09</StartDate> <EndDate>2013-11-08</EndDate> <Link href="/ccus/141705/hires/a1/hires/h101442" method="get" rel="self"/> <Link href="/ccus/141705" method="get" rel="Ccu"/> <Link href="/ccus/141705/hires/a1" method="get" rel="EnclosingHire"/> <Link href="/organizations/123456789" method="get" rel="Organization"/> <Link href="/organizations/123456789/locations/1234567890123" method="get" rel="Location"/> <Link href="/ccus/141705/hires/a1/hires/h101442/documents" method="post" rel="Documents"/> <Link href="/ccus/141705/hires/a1/hires/h101442" method="put" rel="update"/> <Link href="/ccus/141705/hires/a1/hires/h101442/hires" method="post" rel="addHire"/></Hire>
Example Message
47
<Hire id="h101442"> <CcuId>141705</CcuId> <EnclosingHireIds> <EnclosingHireId distance="1">b2</EnclosingHireId> <EnclosingHireId distance="2">a1</EnclosingHireId> </EnclosingHireIds> <OrgNo>123456789</OrgNo> <GlnLocation>1234567890123</GlnLocation> <StartDate>2013-10-09</StartDate> <EndDate>2013-11-08</EndDate> <Link href="/ccus/141705/hires/a1/hires/h101442" method="get" rel="self"/> <Link href="/ccus/141705" method="get" rel="Ccu"/> <Link href="/ccus/141705/hires/a1" method="get" rel="EnclosingHire"/> <Link href="/organizations/123456789" method="get" rel="Organization"/> <Link href="/organizations/123456789/locations/1234567890123" method="get" rel="Location"/> <Link href="/ccus/141705/hires/a1/hires/h101442/documents" method="post" rel="Documents"/> <Link href="/ccus/141705/hires/a1/hires/h101442" method="put" rel="update"/> <Link href="/ccus/141705/hires/a1/hires/h101442/hires" method="post" rel="addHire"/></Hire>
HATEOAS
48
● Uses a lot of bandwidth
● To avoid refactoring something that's easy to refactor
● Infrequent changes
● YAGNI (You aren't gonna need it)
INCONVENIENT TRUTH #5:
Hierarchical URIs will kill you in the end
49https://www.flickr.com/photos/grantmac/4192158869
50Fra: http://martinfowler.com/articles/richardsonMaturityModel.html
Richardson Maturity Model
Example Message
51
<Hire id="h101442"> <CcuId>141705</CcuId> <EnclosingHireIds> <EnclosingHireId distance="1">b2</EnclosingHireId> <EnclosingHireId distance="2">a1</EnclosingHireId> </EnclosingHireIds> <OrgNo>123456789</OrgNo> <GlnLocation>1234567890123</GlnLocation> <StartDate>2013-10-09</StartDate> <EndDate>2013-11-08</EndDate> <Link href="/ccus/141705/hires/a1/hires/h101442" method="get" rel="self"/> <Link href="/ccus/141705" method="get" rel="Ccu"/> <Link href="/ccus/141705/hires/a1" method="get" rel="EnclosingHire"/> <Link href="/organizations/123456789" method="get" rel="Organization"/> <Link href="/organizations/123456789/locations/1234567890123" method="get" rel="Location"/> <Link href="/ccus/141705/hires/a1/hires/h101442/documents" method="post" rel="Documents"/> <Link href="/ccus/141705/hires/a1/hires/h101442" method="put" rel="update"/> <Link href="/ccus/141705/hires/a1/hires/h101442/hires" method="post" rel="addHire"/></Hire>
Composition
● A hire on an asset cannot exist without the asset
● A subhire on a superhire cannot exist without the superhire
● A journey during a hire cannot exist without the hire
● Etc…
52https://www.flickr.com/photos/aspis7/5075169756
Example Hierarchical URI
53
/ccus/734975456/hires/13464654/hires/h101442/journeys/59267932/leg/93246452
Validation #1
54
/ccus/734975456/hires/13464654/hires/h101442/journeys/59267932/leg/93246452
Validation #2
55
/ccus/734975456/hires/13464654/hires/h101442/journeys/59267932/leg/93246452
Validation #3
56
/ccus/734975456/hires/13464654/hires/h101442/journeys/59267932/leg/93246452
Validation #4
57
/ccus/734975456/hires/13464654/hires/h101442/journeys/59267932/leg/93246452
Implied Access Control and Confidentiality Constraints?
58
/ccus/734975456/hires/13464654/hires/h101442/journeys/59267932/leg/93246452
What's the Alternative?
/ccus/734975456
/hires/13464654
/hires/h101442
/journeys/59267932
/leg/93246452
59https://www.flickr.com/photos/aspis7/5075169756
The things I wish I knew
a couple of years ago…
60
INCONVENIENT TRUTH #1:
GET calls are never nullipotent
61https://www.flickr.com/photos/grantmac/4192158869
INCONVENIENT TRUTH #2:
HTTP Verbs ≠ “REST Verbs”
62https://www.flickr.com/photos/grantmac/4192158869
INCONVENIENT TRUTH #3:
HTTP Response Codes ≠ “REST Response Codes”
63https://www.flickr.com/photos/grantmac/4192158869
INCONVENIENT TRUTH #4:
HATEOAS YAGNI⇒
64https://www.flickr.com/photos/grantmac/4192158869
INCONVENIENT TRUTH #5:
Hierarchical URIs will kill you in the end
65https://www.flickr.com/photos/grantmac/4192158869
Thank You for Your Attention!
66
Contact information:
@filipvanlaenen
[email protected] / [email protected]
https://no.linkedin.com/in/filipvanlaenen
http://www.slideshare.net/filipvanlaenen/