Hacker News new | comments | show | ask | jobs | submit login
RESTful thinking considered harmful (shopify.com)
97 points by Titanous 1790 days ago | hide | past | web | 73 comments | favorite

Look, I'm not a REST cheerleader by any stretch of the imagination but in REST terms the OP just doesn't know his ass from his elbow here. Consider:

> POST /orders/42/pay

> POST /orders/42/ship

You don't put verbs in your URLs. This is really REST 101. I highly recommend Nobody understands REST or HTTP [1]. The above is exactly why you don't put verbs in URLs. Consider instead:

    POST /payment { orderId=42, etc }

    POST /shipment { orderId=42, etc }
is a much sounder RESTful API design.

And in case anyone feels the need to suggest SOAP, I highly recommend the satiricial (but disturbingly accurate) The S stands for Simple [2].

[1]: http://blog.steveklabnik.com/posts/2011-07-03-nobody-underst...

[2]: http://wanderingbarque.com/nonintersecting/2006/11/15/the-s-...

Maybe you just skimmed the article, or he's changed it since, but he doesn't say that verbs in URLs was RESTful. He said it was better than RESTful, and I'm inclined to agree with him.

Having tried my hand at designing REST APIs for typical business systems a few times, I've noticed that state machines and transactions are everywhere. Making every resource a noun with the four basic REST verbs leads to a complex and extremely chatty design, whereas slipping a few extra verbs in here and there makes the API simpler, easier to understand, and more efficient.

Placing verbs in your Resftul apis resources is wrong, but it just feels so right....

My thoughts:

1. Most people who think that REST is The Best Thing Evar don't really understand what REST is.

2. Most people who think that REST is terrible don't really understand what REST is.

REST is a tool. It's useful for a lot of things. It can alleviate initial scalability issues. It can make an API easier to use or require fewer calls. It can make it easier or more intuitive for someone to learn an API, and it's very often easier to make changes to a REST API because of the way it is written.

But it's just a tool, and if you can't grok that, you're probably a tool as well.

So only true scotsmen aren't tools? I'd argue that if a concept is so badly explained that both its most zealous proponents and antagonists are mistaken, that perhaps it's not such a useful design concept in the first place.

I mean, who could possibly be confused about what the transfer of representational state means?

We're getting off track here, so I'm going to recuse myself, but I would argue that the most zealous proponents and antagonists of any concepts are likely mistaken, in some way.

since when does a concept need to be easy to explain for it to be great? Ever heard of general relativity or quantum physics?

Those are laws of nature, not design paradigms. They have different (almost opposite) metrics for "great". Relativity (both variants) and QCD are "great" precisely because they were discovered and characterized in spite of the fact that they are counterintuitive and difficult to visualize.

Good software design, on the other hand, is all about human communication. And a design paradigm that can't be communicated easily has less value than one that does.

> But it's just a tool, and if you can't grok that, you're probably a tool as well.

Unnecessary. All tools have a learning curve, a conceptual slope leading to the sweet spot. Being low on the curve does not make one a tool.

I don't believe passing judgement on something you don't fully understand is a good quality to have, even if it gets your blog more hits.

I agree with the "it's just a tool" sentiment in general, but what other great alternatives are there? I haven't had a favorable experience with SOAP, so I can understand why people think REST The Best Thing Evar. This is based on my own experiences, so I may have used SOAP wrong, misunderstood its intentions, etc. Do you have any examples of when SOAP (or another technology) is preferable to REST?

You can write RESTful SOAP, I don't think the two ideas are perpendicular. The problem with SOAP is more implementation than spec - PHP SOAP is different from .NET SOAP which is (slightly) different from Java SOAP, which leads to headaches.

REST is just a style of API. You can write a JSON API that isn't RESTful just as easily, and in some cases a RESTful API is not warranted.

Do you have an example of RESTful SOAP? I think SOAP's lack of situational HTTP method adoption (i.e. it uses GET or POST for everything, vs DELETE/PUT/etc. when appropriate), and the fact that it wraps another envelope around an already available HTTP envelope makes is hard to deem any SOAP implementation as RESTful. I'm not trying to prove you wrong, I'd just like to see an example (a quick google search yielded nothing for me).

REST was initially described in the context of HTTP, but is not limited to that protocol. You could write a RESTful SAML in SOAP in JSON API, if you desired.

Fox Sports has a pretty restful XML API. I can't remember if it's SOAP specifically, though.

I think you may be confused on the meaning of 'perpendicular'

Nope. Guy's got it right. 'Perpendicular' (or 'orthogonal' if you prefer), meaning that the concerns are on separate axes, and thus independent of each other.

SOAP is a bit weird because it's both an envelope/delivery mechanism as well as a discovery/interface negotiation methodology.

REST is just straight up a set of interface design principles. It doesn't care what you're delivering, it doesn't care about the channel you deliver it through.

Um... "You can write RESTful SOAP, I don't think the two ideas are perpendicular." (emphasis mine)

He's saying they aren't perpendicular and also saying they are independent.

RESTful SOAP? To read anything you have to POST the SOAP envelope.

That doesn't make it impossible to do. REST is traditionally implemented on HTTP, but the core goals and methodologies could be implemented over any protocol.

The "other thing" for us is is RPC and PUB/SUB patterns over sockjs (which wraps Websockets+fallbacks).

REST is a tool. But given an engineer a tool like a hammer and pretty soon everything will look like a nail. Sometimes you need a screwdriver when you actually have screws. Hammering them in will work but it is ugly.

Yeah I considered PUB/SUB as another alternative, and it makes sense to use it for realtime applications, but I'm not sure what else (due to my ignorance, not necessarily PUB/SUB limitations). As for RPC, isn't SOAP the successor to that?

"The RESTful thinker may design both the payment of an order and the shipping of an order both as updates"

Maybe this thinker got it wrong. How about POST /orders/42/payment to create a payment object?

Yup. The author is wrong in his assumption. You can always model the "process" parts using a resource(payment resource as against pay, transaction as against credit/debit etc).

My point is not so much that REST is wrong, but that RESTful thinking can be harmful if it comes before thinking about the process you're supporting.

Ok, but what is RESTful thinking?

The way i think about REST is this: here is my stateful application, how can i make it available over HTTP/REST. So i start identifying resources. Most of them are easy - they map to your domains models. But some of the operations on some of the resources are quite important to my application (eg: ordering products, making a payment etc), so i consider creating separate resources for them.

It looks like you are referring to modeling your stateful application when you talk about RESTful thinking.

That's a very good question, what is RESTful thinking?

I personally think so many of us are misguided in our think when it comes to RESTful APIs. In order to make good design decisions for your API you must understand how the users of your API perceive RESTful APIs. In order for you to understand how the users of your API perceive RESTfuls APIs you must consider how the masses (within your target audience) understand RESTful APIs.

Whether your interpretation of RESTful APIs is right or wrong does not matter. What matters is that people can use it. In order for people to use your API it must be easy to understand. In order for it to be easy understand it must be well documented and consistant.

Therefore RESTful API design must be approached on a case by case basis. You must understand your users, their knowledge base, and how capable they are.

wvanbergen: Interesting article. It was thought provoking at the very least.

I think by "RESTful thinking" he means "cargo-culting the Rails RESTful scaffolding".

I think this is a fair point. REST is all about resources and representations, which makes modeling simple CRUD actions on domain objects very easy. However, modeling application processes effectively is harder and requires deeper thought and a more thorough understanding of REST.

I've always thought the key to understanding REST is understanding idempotence. Is HTTP request to mark an order as paid idempotent? If so, a PUT/PATCH should be fine. If not (say, you're actually transferring funds) then a POST should be used. This key principle will help make your URL design choices much easier. In your example, the PATCH API appears idempotent, making the suggested POST replacement sort of confusing to me.

When it comes to modeling application processes using HTTP, understanding which requests are repeatable without consequence and which aren't is very important. It's hard to talk about modeling processes RESTfully without talking about idempotence. It's at the heart of the protocol's design.

RESTful thinking needn't be harmful for application processes as long as you do it effectively.

> to create a payment object?


Also, not sure what's up with TFA's strawmanning,

    PATCH /orders/42 # with { order: { paid: true  } }
    PATCH /orders/42 # with { order: { shipped: true } }
looks like RPC update calls (hey let's map our Ruby attribute updates to HTTP calls, yay!) more than RESTful calls.

Also, not sure why a payment resource would be conceptually "within" an order (although that's got little to do with RESTfullness): why not POST to /payments?order=42? Which would return a link to e.g. /payments/2345 for your actual payment resource?

Something similar to http://blog.steveklabnik.com/posts/2011-07-03-nobody-underst... transaction resources.

Nearly correct. POST does not specify the name of the resource. So you do

  /orders/42 # with { order: { paid: true  } }
And it returns the /orders/42/payment transaction resource.

I disagree. Surely an Order HAS Payments, therefore /orders/42/payment POST is more correct. Likewise orders/42/shipment.

Nicely leading on to /orders/42/payments/1.

REST is a great starting point for an API, but generic REST interfaces (in Rails, Django, or any other framework) are relied on too heavily. I'm especially interested in mobile APIs, which have very specific considerations that REST doesn't answer well.

Building a generic data back-end for mobile is very hot right now, with lots of funded startups in the space. Some of them are just offering a REST API, which frankly any Rails or Django developer could produce in about 10 minutes. Mobile APIs need to be different, mostly due to slow or non-existent connections, and require additional thinking. More details here: http://ow.ly/9YMrM

Anybody know of any mobile back-end providers that are thinking innovatively about this? I've consulted a few of these startups and they all seem hesitant to make any choices that go beyond REST...but as far as I'm concerned, offering a generic solution for something that mobile devs have to develop every time they create an API would be well worth it. A simple example is to accept a guid for every created object and return that guid in the response. It's something you have to do to know that the object has been sent successfully to the server, so why make the developer code it every time?

I do not think your blog examples goes beyond REST. You just need to represent different resources. For example a "title list" or "article set".

That, or a nice way of using different mimetypes to indicate which representation you want.

Also, http status codes perfectly solve the problem of needing to know wether an object was sent to the server successfully. No need to reinvent the wheel and mess with guids imo.

> POST /orders/42/pay

> POST /orders/42/ship

But "pay" and "ship" are actions, not objects, so it doesn't make a lot of sense for them to be represented as URLs.

You hit the nail on the head there. If the author posted a new payment (using whatever metaphor), then a handler could initiate a set of actions in the course of processing <metaphor>.

Maybe this is a real debate in some circles, but I cannot fathom mapping HTTP verbs directly to SQL statements.

Exactly. Having these endpoints instantly turns your API into an RPC-API. This is the start of a snowball of complexity introduced for your consumers.

I understand why that isn't RESTfull, but why is it more complex?

"customers" are used to thinking in terms of actions. You hit this little button here for payment, you hit this other little button here for shipment. And for developers, these are like methods containing business logic belonging to an object.

So where's the problem?

HTTP requests are actions -- that's why they have verbs. URIs should be concepts those verbs act upon.

GET /orders/42/pay is a verb on a verb. Maybe not complex, but definitely confusing.

PAY /orders/42

That's the most natural mapping, the verb PAY on the object of order 42. Maybe HTTP needs arbitrary verbs instead of a limited predefined set? We'd have to get firewalls and proxies and such out of the habit of processing a request depending on its verb.

The point of having limited and well defined HTTP verbs means that you know what to expect. e.g GET has no effect on the resource, while PUT is idempotent, and POST is neither. This precise set of definitions, along with the remainder of REST principles mean that friction is greatly reduced when building/consuming APIs.

There's actually nothing stopping you from using your own verbs, actually; it's allowed. Lloeki gives a good reason not to, though: I don't know how PAY will be handled without consulting documentation.

The HTTP spec is -- it only specifies certain verbs. An implementation need not (and often doesn't) support others.

Isn't how any of the supported HTTP verbs is handled dependant on the API? <consults documentation...>

Yeah, but not totally. For instance, you can always guess what a GET does. There are properties of the established verbs that you can expect.

It's not a problem, but you don't get all the benefits of HTTP if you don't respect REST. This since HTTP is built around the idea of REST.

To me it seems logical to embrace the ideas of the tool you are using. If you are not utilizing the power of HTTP, why not just use a pure RPC protocol?

I think that we eventually have to open up for more protocols if the web continues to develop into a generic dev platform. In a sense we are already heading in that direction with WebSockets. But since HTTP has been and continues to be such a success, I think that we can atleast try to promote it.

This configuration can still be RESTful as long as you POST to those endpoints. The complexity I was referring to is the snowball effect of adding different actions.

If you use hypertext in the resources to specify the places the client can go, the complexity is severely reduced. However, properly enabling discovery is where most "Rest" APIs fail.

> POST /orders/42/payment

> POST /orders/42/shipment


Pretty close. If you really want to make the process "safe" (idempotent, to avoid double posted payments), you might actually have to do something more complicated such as:

GET /order/42/payment/new (returns "3", for example)

PUT /order/42/payment/3 (supplying content for payment info and amount)

Re-issuing the "PUT" (in case confirmation was lost? user double clicked "submit"?) would simply resend the same value, thus, an "idempotent" action.

Viewing this particular payment is simply:

GET /order/42/payment/3

Without the "3", who knows which payment you would get? (unless you got back the list of all payments on the order so far)

I'm not sure if this an argument for or against REST, but I'd sure hate to see a SOAP example typed into a "comment box" in a discussion forum :-)

Good point. I wonder, though-- could you make /order/42/payment the only payment resource related to /order/42, so the ID isn't needed? (PUT /order/42/payment)

If the payment doesn't cover the bill, you could have the PUT respond with a link to /order/42/payment/remaining/1, then (if needed) continue with /remaining/2, and so on.

That would avoid the danger of a gap between your id GET and the payment PUT.

Shouldn't it be:

  POST /payment

  POST(or PUT) /order/42


POST /orders/42?pay=1

POST was always about actions, not just resources.

An HTTP request has two parts: a resource (URL) and a method. Expressing your method in the resource rather than the, um, method muddles the two.

Small thing, but when the author attributes REST to Robert Fleming, I believe he actually means Roy Fielding.

Thanks, will fix.

There's no link for "protecting attribute mass-assignment in the controller vs. in the model".

Must have disappeared when I transferred the article. Fixed, and thanks for reporting.

transferred the article? you write blog posts in word?


Can we please kill the "considered harmful" meme?

X considered harmful is one of computing's oldest memes, 44 years old this month, and was well sort of co-created by two of its foremost computer scientists. (Dijkstra and Wirth)

As memes go, it has a long history.


Yep, that's probably the worst thing about the meme. Because the original was so famous, all others piggy back on it, giving their own arguments some amount of weight.

(off-topic, but goto statements being harmful has been debunked several times over).

Why? When I see "considered harmful" in a title, I know pretty much what kind of article to expect. I think it's a useful shorthand, and that its origins, and the whimsical attitude associated with it, are irrelevant. What alternative title would you suggest for this article?

"Why the merits of REST are overstated"

"Considered harmful" is a flippant way to dismiss detractors.

Especially here where it's cheap linkbait for an article whose actual claim seems to be “Gee, REST is hard to get right sometimes”. Not that I like the inflamed rhetoric of an actual “considered harmful” call to arms, either.

killing memes considered harmful.

The writer seems not to consider several other models such as

PUT /orders/42/payed or POST /orders/42/paymentprocessor

, which in my eyes would be both restful and true to the business model.

Ship with a state machine implementation by default, and a generator for a state machine-backed process model. Be opinionated!

I think this is the most compelling take away. I learned how to use the state_machine gem in my current job, and it's an invaluable tool for going beyond CRUD and building real process models.

State machines are excellent, but this comes up every so often on HN and I've come to respect the observation that state machines become very difficult to change.

They particularly rock for games, where the universe is unlikely to suddenly add new interactions or change fundamental laws, but in an evolving business application with requirements that perpetually jag, they can be a source of great pain.

EDIT: After thinking about this a bit more, I realize the state machine use is in reference to an API, which probably should be approached with a certain sense of immutability. I still think that in general, using them outside of games should be approached with serious fore-thought to the potential for change in your requirements.

Is it just me or are these "considered harmful" articles becoming way too cliche? When I see one, I immediately become suspicious of it's content and distrust it as I've come to associate it with some sort of inflammatory headline or flippant way to dismiss legitimate conversation.


Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact