doing rest right

39
“Come unto me, all ye that labour and are heavy laden, and I will give you REST.” –God

Upload: scott-raymond

Post on 06-Jul-2015

1.835 views

Category:

Technology


0 download

DESCRIPTION

Prepared for RailsConf 2007

TRANSCRIPT

Page 1: Doing REST Right

“Come unto me, all ye that labour and are heavy laden, and I will give you REST.”

–God

Page 2: Doing REST Right

Doing REST RightScott RaymondFirewheel Design

- Thanks for being here, lets get started.- My name is Scott Raymond, I’m with a company called Firewheel Design, and I’m talking today about Doing REST Right.- Let me start with a question or two. First, raise your hand if you have some idea of what REST is, even very roughly. Okay, great. Now, raise your hand if you have built a RESTful application. - I have good news...

Page 3: Doing REST Right

Congratulations!Sort of!

I suspect that, in fact, every single hand in this room should be raised. That's because if you've ever put a single HTML page on the web, you have done REST. Congratulations! You can add another bullet point to your resume!- That's the surprising thing about REST -- it's so prevalent that we hardly even see it. But in fact, it is the default way that the web works.- So if you're already doing it, why are we even here? The answer is that we could all be doing it so much better. The trick is first to recognize how we've been following some of the REST axioms by accident all along, and then we'll start to see how we've been falling short in other areas.- Now before we really get started, let me give you the plan.

Page 4: Doing REST Right

Orthodoxy & Orthopraxy

There's an important distinction between _orthodoxy_ and _orthopraxy_. Orthodoxy roughly means "right teaching" -- having the right _ideas_, thinking the right thing, believing the right thing. It's about what's in your head. Orthpraxy, is a less common word. It means "right practice" -- doing the right thing, behaving correctly, taking the right action. Both are important, but orthodoxy alone isn't worth much if it's never put into practice.

Like any good orthodoxy...

Page 5: Doing REST Right

Like any good orthodoxy, REST has its prophets and its holy texts. (This is a picture...) Whether or not you’ve heard of this guy or read this text, by now I'd guess that most of you have heard some dose of REST orthodoxy, if only just from Rails blogs.

So for the purposes of this talk, I'm going to try to move pretty quickly from the theoretical to the practical. For the most part, I'll assume that you already have the orthodoxy -- that you believe, or at least are willing to grant, that REST is a good thing. REST-style applications are rightfully seen as putting the "web" back into "web services". And you have some idea of the “why”. So what I’m going to focus on is the “how”.

But real quick I want to throw out one other guideline.

Page 6: Doing REST Right

Text

“All models are wrong, but some are useful.”

―George Box

One thought I'd like you to keep in mind through this presentation -- for that matter, through every presentation during the rest of this conference. It's encapsulated in this quote by George Box.

You’ve heard this before called "the law of leaky abstractions" and "the map is not the territory". Right? So for example here’s this famous map...

Page 7: Doing REST Right

So for example here's this famous map of the London tube, where they have conveniently distorted things so that all of the lines are straight, and don't overlap too much, and the stops are evenly spaced.

Page 8: Doing REST Right

And then here's a version that's geographically to scale. Much more hairy, very hard to read in the middle, and very inefficient with whitespace around the outside.

Now, it's tempting to say that this map is the *right* one, but the other map is the *useful* one. But I'd challenge you to see it differently: *both* maps are "wrong". After all, both of them, in some way, purport to compress and entire dynamic city into a few megapixels! But they are both useful. And for a given purpose, they're each useful to different degrees.

Page 9: Doing REST Right

Text

“All models are wrong, but some are useful.”

―George Box

So, when we talk about any kind of model -- not just maps, but any kind of model for understanding the world, it necessarily involves some kind of simplification, some loss of resolution. That's a feature, not a bug. Models allow us to understand and work with an infinitely-complex "real world" by conveniently ignoring certain details. And so competing models shouldn't be necessarily be judged by their precision, but by their usefulness.

REST, as a model of the web, is no different. It glosses over certain realities in order to provide an idealized model of how the web works.

Now, my intent is to make this talk as practical as I can, but I'm already getting all meta on you, so I'm going to *try* to breeze through this next part pretty fast. But I want to talk about REST as the model of the web, because that theory will inform the practical questions we need answers to.

Page 10: Doing REST Right

What REST Isn’t• Pretty URLs•CRUD• respond_to•map.resources•HTTP•A protocol•An architecture

Pretty URLs. There's nothing about /users.php?id=123 that violates REST.

Page 11: Doing REST Right

What REST Isn’t• Pretty URLs

GET http://example.com/users.php?id=123

Here’s an easy misconception to put to pasture.

There's nothing about this URL that violates REST. Ugly, sure, but judged as REST, it’s completely fine.

Page 12: Doing REST Right

What REST Isn’t

CRUD. Rails seems to say that REST==CRUD. And at first glance, it's an easy reduction to make. SQL SELECT maps readily to HTTP GET, and SQL DELETE maps pretty well to HTTP DELETE. But after that, things start to fall apart.

Page 13: Doing REST Right

HTTP CRUD SQL

POST Create INSERT

GET Retrieve SELECT

PUT Update UPDATE

DELETE Destroy DELETE

Here’s the standard table showing how REST maps to CRUD.

The problem is that this isn’t quite right. For example, PUT isn’t strictly for updating existing resources -- it can also create new ones. Same with DELETE -- it’s perfectly valid to send DELETE for some resource that doesn’t exist. And the semantics of POST are significantly more vague than simply creating -- it can also be understood as “append”, or even more generally, just “process this”.

Page 14: Doing REST Right

HTTP CRUD SQL

POST Create INSERT

GET Retrieve SELECT

PUT Update UPDATE

DELETE Destroy DELETE?Here’s the standard table showing how REST maps to CRUD.

The problem is that this isn’t quite right. For example, PUT isn’t strictly for updating existing resources -- it can also create new ones. Same with DELETE -- it’s perfectly valid to send DELETE for some resource that doesn’t exist. And the semantics of POST are significantly more vague than simply creating -- it can also be understood as “append”, or even more generally, just “process this”.

Page 15: Doing REST Right

What REST Isn’t

• respond_to•map.resources

respond_to and map.resources. Rails has done a ton to embrace REST, and as a result, some developers are conflating what's *actually REST* with Rails' implementation of REST. In fact, I've been guilty of this myself -- I wrote a blog entry last year called "Refactoring to REST" which implied that you could make your application RESTful just by rewriting your routes.rb file to use map.resources. Along the same lines, REST isn't really related to how your organize your actions in your controllers, although designing your application with REST in mind does *help* you keep your controllers nice and tidy.

Page 16: Doing REST Right

What REST Isn’t•HTTP•A protocol•An architecture

HTTP. This one might be a bit of a surprise, because HTTP and REST are kind of incestuous. REST and HTTP are at two different levels of abstraction. HTTP is probably the most RESTful protocol, largely because REST was a post-hoc description of early HTTP, and HTTP 1.1 was designed with REST in mind. But it's entirely possible to judge the RESTfulness of other protocols, or to design new protocols with REST principles in mind.

A protocol or a standard. There's no spec to implement or suite of tests to pass. But REST systems *rely* on standards all over the place -- in the case of the web, URLs provide a standard addressing mechanism, HTTP provides a generic interface, and any number of standard media types are used for the content.

An architechture. from REST book: "That's because it presents REST not as an architecture but as a way of judging architectures. The term "RESTful" is like the term "object-oriented". A language, a framework, or an application may be designed in an object-oriented way, but that doesn't make its architecture the object-oriented architecture."

One last one that's not on this list: REST is not really comparable to SOAP. They aren't even really the same kind of thing. comparing REST with SOAP is like comparing object-orientation with some particular language.

Page 17: Doing REST Right

So What is REST?

Obviously, REST is an acronym, but it might as well not be, because knowing what it stands for doesn't really help understand what it is. So I'm not even going to bother you with what it stands for. Instead, let me throw out as succinct of a definition of REST as I can, and then I'll unpack it a bit. Here it is: REST is the architectural style of the web.

Okay, so it’s not an architecture, but it’s an architectural style? Spitting hairs, huh?

Page 18: Doing REST Right

the architecturalstyle of the web

So What is REST?

Obviously, REST is an acronym, but it might as well not be, because knowing what it stands for doesn't really help understand what it is. So I'm not even going to bother you with what it stands for. Instead, let me throw out as succinct of a definition of REST as I can, and then I'll unpack it a bit. Here it is: REST is the architectural style of the web.

Okay, so it’s not an architecture, but it’s an architectural style? Spitting hairs, huh?

Page 19: Doing REST Right

Communication Theory

REST

Web Architecture

Implementation

A B S T R A C T

C O N C R E T E

Roy said thisabout REST's place in the world: "Communication theory is a lot more abstract than REST, REST is a lot more abstract than Web Architecture (URI, HTTP, HTML, ...), and Web Architecture is somewhat more abstract than any current implementation of that architecture (Apache httpd, Mozilla Firefox, etc.). And yet they all need to influence each other, in various ways, when we attempt to design changes to a living system."

So take a look at that. It's saying that REST is pretty high up on the abstractness scale. The upshot?

Page 20: Doing REST Right

More what you’d call “guidelines” than actual rules.

You can't bottle REST, or sell it, or even implement it, per se -- it's not a product, a protocol, a format, a specification, a standard, or a stack. It's a style. An architectural style. And as such, there is not really a definitive, black and white, concrete instance of REST -- not even in theory.

In theory, you could come up with a perfect, to-the-letter implementation of HTTP, and essentially prove that it was perfect. That's not true of REST, because it deals at a higher level of abstraction. As such, particular implementations are judged on their *degree* of RESTfulness.

So REST gives us these guidelines. And in some way, all of them center around the concept of Resources.

Page 21: Doing REST Right

What’s a Resource?

Simple answer: anything that can be named. I'm a resource, you're a resource. "The weather where I am right now" is a resource, too (notice how that's not static -- it's constantly in flux, and it depends on where I'm standing. But it can be named, so it's a resource. There could also be another resource, called "the weather in portland on the morning of May 18". One of those resources changes over time, and the other will never change. Even though they both have the same value right now, they're separate concepts, and so they're separate resources.- If you want to think of REST in object-oriented terms, resources are just objects, except that they all have to have the same, small number of methods. The key argument of REST is that that small number of methods is sufficiently general for anything you'd want to do. There are tradeoffs with that approach, to be sure -- REST does not claim to be the one true architectural style. But if what you're building is an internet-scale distributed application, the REST style offers a lot of benefits.- One other key element is the distinction between resources and representations.

Page 22: Doing REST Right

Representations, shadows in Plato's cave.

Page 23: Doing REST Right

IDENTIFICATION ADDRESS

INTERACTION METHOD

CONTENT DATA

The nuts and bolts of doing REST right happen along three aspects.- The first is _identification_, or _address_, or _scoping_ information. This is the part that answers the question, what is being acted upon? - The second aspect is _interaction_ or _method_ information. This is the part that answers the question, what action is being taken?- The third aspect of any message scheme is the content, or data, or media type.- Lets buzz through these three aspects one by one. Okay, so we'll start with the easiest part first, identification. In REST, identification is done with URLs, which are just names.

Page 24: Doing REST Right

My Name is URL.

HTTP methods are like verbs. URIs are like nouns. I.e., names for things.

Remember, the name is not the thing itself.

So identification is easy; lets move on to interaction.

Page 25: Doing REST Right

The Uniform Interface

In most message schemes (like SOAP, or OO programming in Ruby), the interaction aspect is virtually unconstrained -- each type of object supports its own vocabulary of interactions (i.e., method names). But in REST, this spaces is restricted to a small set of generic, pre-defined interactions; if you hear people talking about the "uniform interface", this is what they're talking about.- Now, the REST style doesn’t actually say that those methods must be GET, POST, PUT, and DELETE. It just says that there should be a small set of methods that are the same for every resource. But on the web, those are the methods we’ve got, so lets talk through them a bit.- We’re all pretty familiar with GET and POST, and we know that the difference between them has something to do with “safety” and “idempotence”, but those terms feel vague.

Page 26: Doing REST Right

Is it safe?! Is it idempotent?!

- GET is the only method that’s safe. And GET, PUT, and DELETE are all idempotent.- Safe means no side effects, “incurs no obligations.”- idempotent means that performing the action many times has the same effect as performing it once. like abs.- POST neither safe nor idempotent. is the most general, the bluntest, of the HTTP methods, and therefore the most powerful, and therefore the one to be most careful with. You can cram almost anything into POST, but you shouldn't. Use it as the method of last resort.

Page 27: Doing REST Right

Content

So of the three aspects that REST deals in, we’ve looked at Identification and Interaction, and seen that the path is pretty well-paved: you always use URLs for scoping information, and always use the uniform interface for interaction. - That leaves the third spoke, content. And if you're doing it right, the third slice is where you should be spending most of your effort, because content types are hard, and open ended. REST intentionally pushes all of the hard problems into this slice.- The first key word here is standards. And that’s where most Rails-based REST APIs, including ones I’ve built, need improvement. This is where my personal opinions diverge most from Rails’ opinions. to_xml is like scaffolding -- it’s great to get you up and running, but probably not what you want in the end. Never invent a new XML vocabulary if you can avoid it.- Second key point about content: it should contain links. This is what's referred to when people say "hypertext as the engine of application state." To get abstract on you, you can view the web as one big state machine, and the "page" you're on tells you about all of the other application states that you can move to, via links. (Refrain (repeat this with other key tenets elsewhere): if your content doesn't have a lot of HREFs, you're not doing it right. [where does this leave standard-but-non-hypertext media types, like vcard?]).- So now I’d like to propose some typical questions that Rails developers will face when trying to build RESTfully.

Page 28: Doing REST Right

How can I update several resources at

once?

- For example, say you've got a todo list, with checkboxes. One POST of the form needs to update multiple resources, so what URL does it target?- You're wanting to scope a request to something other than one resource. There’s the clue, the keyword “scope”.- So you need to give that resource a name. Where do names belong? In URIs! so the solution is to make up a name (a URL) for the scope that you're wanting to update, and then PUT to that.

Page 29: Doing REST Right

How can I do partial updates?

is it in the semantics of PUT that the PUTted representation will be identical to what can be GETted immediately thereafter? in other words, is it okay for me to PUT a partial invoice rep, or a full one with some amount of invalid information? or should those requests result in an error? This is boils down to a scoping problem -- you're wanting to address a subset of some resource. where does scoping information belong on the web? in URIs! so the likely solution is to make up a name for the scope that you're wanting to update, and then PUT to that. I say you PUT a partial representation. some people disagree, saying you should only PUT a full representation. (does HTTP or the thesis address this?)

Page 30: Doing REST Right

I’m special; I need more than GET/POST/

PUT/DELETE semantics.

"But my model is different!". You are not a special or unique snowflake.

- should I build another protocol?- should I add a new HTTP method?

- answer 1: tough shit. you're wrong, it can be modeled with the uniform interface, it's sufficiently general.

Page 31: Doing REST Right

How should I do authentication?

- Cookies are often frowned upon in REST circles, because they’re so often abused. Think of the old Rails session mechanism.- HTTP basic auth kinda blows. HTTP digest is better in some ways.- Cookies aren’t necessarily bad. The new Rails default is to store sessions entirely in the cookies -- not just a session ID, but the whole session data. This rocks. It means that by default, your session-based auth is RESTful.- But for non-browser clients, you’ll probably want Basic or Digest as well.

Page 32: Doing REST Right

Should I include content-type info in

the URL?

- answer 1: no. answer 2: yes- It's a trade-off. if you do, you can create straight browser links to specific representations, which is pretty essential. but the downside is that you're limiting the network effects. So proceed with caution- This is an example of the kind of issue where it’s important to question Rails’ assumptions. We all know Rails is an opinionated framework, which is often a great thing. But you’re allowed to have opinions too. And when it comes to your user interface, don’t let Rails push you around. And there’s a corrollary: URLs are UI. The new routes.rb stuff that David demo’d this morning are great, but I caution you to not unquestioningly follow the Rails-standard path when it comes to your URLs, because it’s quite likely that your URLs will far outlive your implementation -- maybe even Rails itself.

Page 33: Doing REST Right

What about reliability?

If you're using HTTP methods correctly, reliability is very easy for 3 of the four methods. Remember that GET, PUT, and DELETE are idempotent. When you hear people use that word, you can translate it to "if at first you don't succeed, try, try again.". So if you do a PUT and something breaks down so that you don't get a response, there's no reason not to just re-PUT the request.

With POST, it's not so simple. What if you POST something and get no response? you can’t know if the POST was received or not, so you can't just try again, and you can't GET it, because you don't know the new URL.

the solution is to break the request into two phases -- first PUT [or POST, arguably] to a "resource generator" URL, which will respond with a new URL in the "Location" header, to which the client re-submits the request. If the second request fails, the client can just continue to re-PUT the message with no worries, or GET it to verify that it worked.

Page 34: Doing REST Right

What about concurrency?

If you do two PUTs at once, one wins.

The solution depends on what you need. For a lot of applications, "last update wins" is a fine strategy. If not, Etags are the solution.

Page 35: Doing REST Right

What about transactions?

I want to debit one guy's account at the same time, and only if, I can credit another guy's account. I could do two PUTs in a row, but that's begging for inconsistencies to creep into the system.

answer 1: YAGNI. Answer 2: what you probably want is a new resource to encapsulate the transaction.

Page 36: Doing REST Right

I need more than one representation with

the same media type.

Can one resource to have two representations of the same type? (eg, an ad-laden HTML view and a printer-friendly HTML view?)

Answer 1: I don't know. Answer 2: make a new URI.

This is a good reason to think twice before making your "API" media type be application/xml, which is the Rails default. Because what happens when you realize that there are actually two XML-based representations that you want to provide for a resource? “application/xml” is about as vague as you can get -- so whenever possible, always try to be more specific.

Page 37: Doing REST Right

How do I handle asynchronous operations, like notifications?

answer 1: polling. Answer 2: callbacks

Give an app a callback URL for certain events. Blog example. Wishlist example: it'd be great if when I entered a new twitter messaage, it would POST it to a URL of my choice, so that I could integrate it with my blog etc., and not have to poll.

Page 38: Doing REST Right

There is no API.

- I started this talk by pointing out that, whether you know it or not, you have almost certainly built something RESTfully -- because if you ever even put a single static page on the web, it's inherently RESTful. So the work becomes recognizing what you're already doing that has been right all along, understanding the principles, and then putting those principles into deeper practice. - So I’ll wrap up where we started. You’ll find that the closer you move to REST, the less of a distinct API you’ll have at all. The “regular” application and its API will become one.- The rub, and it’s a big rub, is not a technical one but a social one. Building on a API requires trust of stability, and “traditional” websites don’t provide for that expectation. Hence the need for documentation. Like all human communication, these are problems can’t be completely solved by any formalized system -- it always, eventually boils down to people.

Page 39: Doing REST Right

RESTful WebServices Ajax on Rails

Unrelated, but By Me!New!

[email protected]

Now, I’ll leave you with a bit of product placement. The book on the left is hot off the presses, by Leonard Richardson and Sam Ruby, and it’s the best single resource I can recommend to fully understand REST. The second book is mine, and it scarcely touches on REST at all, but I recommend it regardless. :-)

Thank you!