the rest and then some

59
Introduction GET /presentation HTTP/1.1 HTTP/1.1 200 OK Content-Type: application/json { "what": "The REST And Then Some", "where": "Nordic APIs 2016 Platform Summit", "when": "2016-10-25T14:40+02:00" }

Upload: nordic-apis

Post on 09-Jan-2017

29 views

Category:

Technology


0 download

TRANSCRIPT

Git

IntroductionGET /presentation HTTP/1.1

HTTP/1.1 200 OKContent-Type: application/json

{ "what": "The REST And Then Some", "where": "Nordic APIs 2016 Platform Summit", "when": "2016-10-25T14:40+02:00"}

Hello! Thank you all for coming. I'm going to talk a bit about REST and hypermedia today.1

Asbjrn UlsbergBusiness Architect

Web, API, Interfaces

Im Asbjrn Ulsberg,Business Architect for Web, API design and interfaces.In PayEx.2

History

Now that we have looked a bit at what REST is not, let's try to figure out what it is.3

1941The Garden of Forking PathsJorge Luis Borges

The Argentinian author Jorge Luis Borges. (Horxe Luis Borxes)Started thinking about hypertext concepts in the 1930s1941: The Garden of Forking Paths: The first black on white reference to hypertext.About the Chinese Doctor Yu Tsun, a former professor of English, now a German spy in England during World War 1.Tsun can take multiple possible actions, but regardless of what actions he takes, he will always end up being arrested by Captain Richard Madden.The Library of Babel and The Book of Sands expands on the hypertext ideas.4

RPG

The same concept as The Garden of Forking Paths can be found in modern RPG-style games like Bioshock Infinite and Fallout 3, where each decision forks the story in a new direction.

5

HypertextHypermedia1963

1963:Ted Nelsoncoined the terms 'hypertext' and 'hypermedia' in a model he developed for creating and using linked content(first published reference 1965).1967: worked with Andries van Damto develop theHypertext Editing System(text editing) atBrown University.6

1968The Mother Of All DemosoN-Line System

In December 1968, the first public demonstration of a hypertext interface was performed by Douglas EngelbartoN-Line Systemor more commonly, NLS."The Mother of All Demos: Mouse pointer, hypertext editing, word processing, e-mail and a windowing environment.Word processing was bornMany of Engelbart's team members went on to start the Palo Alto Research Center, known as Xerox PARC, in 1971:http://www.thocp.net/biographies/engelbart_douglas.html

7

1987

In 1987, Bill Atkinson at Apple Computer created HyperCard.It was a successor to lots and lots of things:Xcode before Xcode (programming environment)AppleScript before AppleScript (near-english programming language)Java before Java (JIT)Interface Builder before Interface Builder, which was Visual Basic before Visual Basic.Flash before Flash (animations)FileMaker before FileMaker (build databases)Built-in debuggerFix and continue before fix and continue8

1989WorldWideWeb

Tim Berners-Lee1989: Develops "WorldWideWeb at CERN, on a NeXTStep computer.1991: HTTP 0.9, Formal description, no status codes, GET only.1996: HTTP 1.0, RFC 19451997: HTTP 1.1, RFC 20681998: Dave Winer utvikler og publiserer XML-RPC1999: HTTP/1.1 RFC 26162015: HTTP/29

2000Architectural Styles and the Design of Network-based Software Architectures

ByRepresentational State TransferRESTRoy Thomas Fielding

The co-author of foundational specifications such as HTTP/1.1 (RFC 2616) and URI (RFC 2396)2000: Roy Fielding doctorate dissertationArchitectural Styles and the Design of Network-based Software ArchitecturesChapter 5: Representational State TransferREST10

Defining REST

What is REST, exactly?Difficult to answer.What I do know is that it is surrounded with a lot of misconceptions.I wish I had time to go through them all, but Ive picked a couple of the most common ones here.11

POSTDoes something with the resourceGETRetrieves the resourcePUTReplaces or creates the resource.PATCHGiven right state in client, apply a diff operationDELETEDelete the resourceDefining REST: CRUD

The first misconception Ive chosen is that REST maps directly to CRUD. It doesnt.Without going into the details about REST being an architectural style and not a protocol, lets go through the methods.POST can create, manipulate or represent any method. It is used to tunnel the whole SOAP protocol, for instance.PUT can both create and replace, but not really update a resource.Only GET and DELETE map, the rest of the methods does something completely different.Secondly, focusing on CRUD will lead to a badly designed API.12

Defining REST: URIshttp://api.com/harddrives/format?drive=c

http://api.com/orders/getOrderById?id=13

http://api.com/orders/13/edit-form

http://api.com/orders/13

http://api.com/731bef1e-8ffa-11e6-96e8

The second misconception is about URIs.URIs, then. Are they important?Which of these are most RESTful?RESTful URI: You have no idea.That doesnt mean pretty and human readable, consistent URIs arent important.But from a REST perspective, it is just an opaque identifier.You will discover URIs through hypermedia, so what it is shouldnt matter one ounce.What's important is what surrounds the URI, such as the:methodinput dataresponse13

Defining REST: URIsURIMethodDescriptionhttp://api.com/v1/customersPOSTCreates a new customerhttp://api.com/v1/customers/{id}GETRetrieves customerhttp://api.com/v1/customers/{id}PUTUpdates customerhttp://api.com/v1/customers/{id}DELETEDeletes customerhttp://api.com/v1/customers/{id}/ordersGETRetrieves customers ordershttp://api.com/v1/customers/{id}/notesGETRetrieves customers notes

Does this look familiar?Who thinks this is good API documentation?If your API is overly concerned with URIs and enumerating them in the documentation, you don't have a RESTful API.You have what Stefan Tilkov calls a URI APIThe bad thing about this is that you burden the clients with server details, while giving up control over something the server should be master of.14

Defining REST: URIs

Let's say you have a database tableWouldn't it be annoying if you couldn't rename it because a client you didn't control had the table name hard coded in its SQL statements?15

Defining REST: URIs

The right spelling of Referer is with two r's, but since you've made the clients dependent on your spelling error, you can never rename the table.16

Defining REST: URIsURIMethodDescriptionhttp://api.com/v1/customersPOSTCreates a new customerhttp://api.com/v1/customers/{id}GETRetrieves customerhttp://api.com/v1/customers/{id}PUTUpdates customerhttp://api.com/v1/customers/{id}DELETEDeletes customerhttp://api.com/v1/customers/{id}/ordersGETRetrieves customers ordershttp://api.com/v1/customers/{id}/notesGETRetrieves customers notes

You have what Stefan Tilkov calls a URI APIThe bad thing about this is that you burden the clients with server details, while giving up control over something the server should be master of.17

Defining REST: URIsURIMethodDescriptionhttp://api.com/v1/customersPOSTCreates a new customerhttp://api.com/v1/customers/{id}GETRetrieves customerhttp://api.com/v1/customers/{id}PUTUpdates customerhttp://api.com/v1/customers/{id}DELETEDeletes customerhttp://orders.com/orders-for-customer/{id}GETRetrieves customers ordershttp://api.com/v1/customers/{id}/notesGETRetrieves customers notes

It's the same way with URI-dependent APIs.If you want to move a resource to a different URL, every client needs to be updated.18

Defining REST: URIsURIMethodDescriptionhttp://api.com/v1/customersPOSTCreates a new customerhttp://api.com/v1/customers/{id}GETRetrieves customerhttp://api.com/v1/customers/{id}PUTUpdates customerhttp://api.com/v1/customers/{id}DELETEDeletes customerhttp://orders.com/orders-for-customer/{id}GETRetrieves customers ordershttp://api.com/v2/customers/{id}/notesGETRetrieves customers notes

If you want to make a backward incompatible change to the notes resource, you give it a new version number.19

Defining REST: URIsURIMethodDescriptionhttp://api.com/v2/customersPOSTCreates a new customerhttp://api.com/v2/customers/{id}GETRetrieves customerhttp://api.com/v2/customers/{id}PUTUpdates customerhttp://api.com/v2/customers/{id}DELETEDeletes customerhttp://orders.com/orders-for-customer/{id}GETRetrieves customers ordershttp://api.com/v2/customers/{id}/notesGETRetrieves customers notes

You now need to give all resources a new version, even though they didnt change.Do tedious work on your URIs and what operations you can perform on themDont write it down in documentation.Write it down into your resources instead, as inline hypermedia controls.Makes the resources self descriptive, decouples the client from the server and makes the server much more flexible in what it can do.

URI templates are for APIs what GET is for HTML.

20

What is the best practice for versioning a REST API?

Roy Fielding gave a talk for the Adobe Evolve conference in 2013There, he proposed the following question: What is the best practice for versioning a REST API?His answer?21

Dont

https://www.infoq.com/articles/roy-fielding-on-versioning/22

REST

So, now that we know what REST is not, lets discuss what it might be.23

RESTI feel warmer and more relaxed in Spanish

I like to think of learning REST like learning a foreign language.A study called:"The Foreign-Language Effect: Thinking in a Foreign Tongue Reduces Decision Biases(by Boaz Keysar, Sayuri L. Hayakawa and Sun Gyu An in Psychological Science)http://www.economist.com/blogs/johnson/2012/05/foreign-languages-and-thinkingProves that different languages affect how we think, act and feel.24

RESTGerman makes me reason more carefully

The same applies to architectural principles and programming languages.Who here knows functional programming?Would you say it makes you think and develop differently than you do (or did) with procedural languages?It at least means that you can't use your RPC competency and just apply it to REST.You will fail.25

REST: ConstraintsClient-ServerStatelessCacheableLayeredCode on demand (optional)Uniform InterfaceIdentification of resourcesManipulation of resourcesSelf-descriptive messagesHypermedia as the engine of application state (HATEOAS)

REST consists of 6 constraints.Another way to look at it: Guarantees.26

REST: ConstraintsClient-ServerStatelessCacheableLayeredCode on demand (optional)Uniform InterfaceIdentification of resourcesManipulation of resourcesSelf-descriptive messagesHypermedia as the engine of application state (HATEOAS)

Of all the constraints, I believe the last one here is both most important and less understood.That's why I'm going to try to explain it.27

RESTHypermedia as the engine of application state is a REST constraint. Not an option. Not an ideal.

Hypermedia is a constraint. As in, you either do it or you arent doing REST.

In an 2014 interview with Mike Amundsen, Roy Fielding said this.https://www.infoq.com/articles/roy-fielding-on-versioning/28

Hypermedia

Links and operations29

Hypermedia: Affordances

Those links and operations are analogous to real-life affordances, as popularized by Don Norman in his book the "Design of Everyday things.Like a cup wants to be held and lifted and a button wants to be pushed, hypermedia should explain to the client what the resource wants the client to do.30

Hypermedia: AffordancesDo people know what to do based on what they see?

Don Norman defines an affordance by Do people know what to do based on what they see?31

Hypermedia: AffordancesDo machines know what to do based on what they see?

In the same way, we can define hypermedia by do machines know what to do based on what they see.

32

Hypermedia

Toaster

Toaster

Turn on

So, how does hypermedia look like?Does it look familiar?Forms are hypermedia recipes of how the next request is going to look likeHow do we transport our knowledge of hypermedia in HTML to an API?

33

Hypermedia

Toaster

Toaster

Turn on

Let's start by reformatting the HTML34

Hypermedia

Toaster

Toaster

Turn on

Replacing all attributes with common ones, makes it more consistent and more "API-like".35

Hypermedia

Making further adjustments36

Hypermedia

{ "id": "/toaster", "title": "Toaster" }{ "image": "toaster.jpeg", "title": "Toaster" }{ "video": "toaster.mp4", "title": "Toaster" }{ "operation": "/toaster", "method": "PUT", "rel": "on", "expects": { "state": "on" }}

Hypermedia

{ "id": "/toaster", "title": "Toaster" }

{ "image": "toaster.jpeg", "title": "Toaster" }, { "video": "toaster.mp4", "title": "Toaster" }

"operation": { "rel": "on", "method": "PUT", "href": "/toaster", "expects": { "state": "on" } }

38

Hypermedia{ "id": "/toaster", "links": [ { "image": "toaster.jpeg", "title": "Toaster" }, { "video": "toaster.mp4", "title": "Toaster" } ], "operations": [{ "rel": "on", "method": "PUT", "href": "/toaster", "expects": { "state": "on" } }]}

Like generating a new WSDL in the response to every request.Just like HTML.39

Hypermedia: State Machine

So, how can we use hypermedia in practice?As REST defines, hypermedia should be the engine of application state.Heres what that means.40

Hypermedia: State Machine

Let's use a toaster as an example41

OnOffShutting downShut DownOffShut DownUpper LimitLower LimitHeatingIdle

Do/Turn Off Heater

Turn On

Initial state of a toaster is Off.We turn it on, and it reaches on status, eventually heating our bread.After it has been heating for a while, it reaches an upper temperature limitBringing it into an idle state.When it reaches a lower temperature limit, it will go back into heating state.Eventually, the bread will be done and the toaster will enter the shutting down stateEnding in the off state, just as we started.42

OffGET /toaster HTTP/1.1

If we turn our toaster into an HTTP resource, how does it look like?Let's try to GET it.43

OffHTTP/1.1 200 OK

{ "id": "/toaster", "state": "off", "operations": [{ "rel": "on", "method": "PUT", "href": "/toaster", "expects": { "state": "on" } }]}

We can see that it has an off state44

OffHTTP/1.1 200 OK

{ "id": "/toaster", "state": "off", "operations": [{ "rel": "on", "method": "PUT", "href": "/toaster", "expects": { "state": "on" } }]}

We can also see that it has an operation that allows us to turn it on45

Off

PUT /toaster { "state": "on" }

Let's look at that operation a little more closely46

Off

PUT /toaster { "state": "on" }

If we just reformat it a little47

Off

PUT /toaster { "state": "on" }

It starts looking like an HTTP request48

OffTurn OnOn

PUT /toaster HTTP/1.1

{ "state": "on" }

HTTP/1.1 200 OK

{ "id": "/toaster", "state": "on", "strength": 0, "operations": [{ "rel": "off", "method": "PUT", "href": "/toaster", "expects": { "state": "off" } }, { "rel": "strength", "method": "PUT", "href": "/fcef93ba988011e6833f", "expects": { "strength": [1, 2, 3, 4, 5, 6] } }]}

Well, look at that! The toaster is now on.We see that we can now turn it off again, but we can also increase the heating strength.By the way, does anyone notice anything different hre49

On

PUT /fcef93ba988011e6833f { "strength": [1, 2, 3, 4, 5, 6] }

Well, look at that! The toaster is now on.We see that we can now turn it off again, but we can also increase the heating strength.By the way, does anyone notice anything different hre50

On

PUT /fcef93ba988011e6833f { "strength": [1, 2, 3, 4, 5, 6] }

Well, look at that! The toaster is now on.We see that we can now turn it off again, but we can also increase the heating strength.By the way, does anyone notice anything different here?51

OnHeatingHTTP/1.1 200 OK

{ "id": "/toaster", "state": "heating", "strength": 3, "operations": [{ "rel": "off", "method": "PUT", "href": "/toaster", "expects": { "state": "off" } }, { "rel": "strength", "method": "PUT", "href": "/fcef93ba988011e6833f", "expects": { "strength": [1, 2, 3, 4, 5, 6] } }]}

PUT /fcef93ba988011e6833f HTTP/1.1 { "strength": 3 }

Ah. The toaster is now heating at strength 3.We see that we can still turn it off and adjust the strength.But what about that ID up there? Doesn't that look suspiciously like a URI?52

Heating

/toaster

53

Upper LimitIdle

Do/Turn Off Heater

HeatingHTTP/1.1 200 OK

{ "id": "/toaster", "state": "idle", "operations": [{ "rel": "off", "method": "PUT", "href": "/toaster", "expects": { "state": "off" } }, { "rel": "strength", "method": "PUT", "href": "/fcef93ba988011e6833f", "expects": { "strength": [1, 2, 3, 4, 5, 6] } }]}

GET /toaster HTTP/1.1

It seems the toaster has reached an upper temperature limit, putting it into an idle state.Although it may look like it, we did not alter the state of the toaster with our GET request.We just discovered that the state had changed, by doing a safe, idempotent request.54

Shut DownShutting downIdle

Do/Turn Off Heater

GET /toaster HTTP/1.1HTTP/1.1 200 OK

{ "id": "/toaster", "state": "shutting-down", "operations": []}

Let's repeat the GET request and see what's happened.Seems like our bread is done and the toaster is shutting down.We now have no available operations, since we can't do anything while the toaster is shutting down.55

Shutting downGET /toaster HTTP/1.1OffHTTP/1.1 200 OK

{ "id": "/toaster", "state": "off", "operations": [{ "rel": "on", "method": "PUT", "href": "/toaster", "expects": { "state": "on" } }]}

56

{ "id": "/toaster", "state": "off", "slot": "/toaster/slot", "operations": [{ "rel": "on", "method": "PUT", "href": "/toaster", "expects": { "state": "on" } }]}

Getting back to versioning, when you use hypermedia, you're much more flexible:Adding properties to JSON is fine.Adding relations to new resources is fine.Adding new representations to the same resource is also fine.So we have a lot of ways we can guide new clients to new content without:Affecting old clientsAdding a version number to our URIs

57

Questions?

Thank You! - @asbjornu - [email protected] - slack.httpapis.com

Asbjrn Ulsberg

You can reach me on:TwitterE-mailSlack. Join the HTTP API slack! It's full of great people in love with the web and APIs.59