Live data from Hacker News

REST Anti-patterns

marcelo-cure.blogspot.com

121–130 of 133 posts

Re: REST Anti-patterns

#121

Question 1#: Is there a reason PATCH is used (or even needed?), instead of PUT to update records? (Create, Read, Update & Delete => POST, GET, PUT & DELETE) seem like a natural fit, why complicate things? Question 2#: What is the consensus around custom verbs? While I've never gone down this route, a few times I have been tempted.

Re #1, PATCH is useful because PUT requires that you replace the entire resource even if you just want to change one little thing and to do that safely, you need the now-current-latest representation of the full resource. A common case is looking at resource A, which is related to resource B (and therefore you have B's ID, but not its full data), you can patch resource B specifying just its ID and the change that you want to make without having to fetch the whole thing first.

Also, PUT can conflict (or overwrite changes) if something else has altered the resource since you fetched it. PATCH is more granular, so you can make it a lot less likely to conflict or overwrite (in addition to being more efficient).

Re #2, I don't know about consensus, but usually when I think that I could use a custom verb, some more thought reveals that I could instead use a standard verb on another resource that I haven't spec'd out yet (like the comments about having a 'transaction' resource representing details of a transaction instead of a 'transfer' verb).

Re: REST Anti-patterns

#122

Question 1#: Is there a reason PATCH is used (or even needed?), instead of PUT to update records? (Create, Read, Update & Delete => POST, GET, PUT & DELETE) seem like a natural fit, why complicate things? Question 2#: What is the consensus around custom verbs? While I've never gone down this route, a few times I have been tempted.

Hypothetically, with PUT, whatever you send to the server should now comprise the entirety of that resource. So if all you PUT is a last name to /people/4335, then all of a sudden person 4335 consists of nothing more than a last name alone in the void, and not even blank fields beside. With PATCH, on the other hand, you can confidently send the value of just one updated field, without your users worrying about their metaphysical well-being.

Re: REST Anti-patterns

#123
Useful article for someone needing help in revising a URI naming scheme, but beyond that could end up being harmful to that person's greater understanding of building "RESTful" systems.

For example, in the Idempotency section, the author states that for GET requests "no change in application state should occur" which is good, but then also states "the response should always be the same" which is incorrect. There's nothing that says the response cant change, if the resource has changed, but the constraint is that it cant cant _as a result_ of the GET request. This is an important distinction.

DELETEing a resource twice, the second delete should be a NOOP, not a 404.

There's some excellent NDC Oslo & London talks covering more in-depth RESTful topics that I'd recommend checking out if the content of the article is an eye opener for you.

https://vimeo.com/131631886 https://vimeo.com/131196782

Re: REST Anti-patterns

#124

The initial and fundamental problem is a misapplication of REST. To take advantage of REST, you need some form of hypertext, not raw JSON APIs. Additionally, on a practical level, you need the end points to be relatively coarse grained, which can be achieved if you design the API for your UI use case, rather than general data access: http://intercoolerjs.org/2016/01/18/rescuing-rest.html Shoehorning HATEOS in JSON AP…

The issue with HATEOAS is a little overstated. You don't need a full AI with independent agency. What you need is a clear media type that corresponds to some domain concepts that both the client and server agree on. The client and server don't even have to totally agree, as long as there is some overlap. The server may provide functions that the client doesn't care about, and the client may care about functions that the server doesn't provide (but are provided by another server). Failure cases are:

- media types totally disjoint (this wouldn't work for a human either, since the server couldn't do anything that the user wants to do with the resource)

- media type misunderstandings - there is overlap in the functions, but what the client intends and what the server does are two different things, because their concept of that domain function is different (that would also be the same problem for a human)

- media types undefined - everyone is just passing random unlabeled JSON globs, so any domain concepts have to be hardcoded equivalent on both sides (this is one case where a human might be able to intuitively guess the right thing, but only if their mental model happens to match the server's model)

The solution is to document the domain concepts of the media types that fit your domain from both perspectives, find the places that don't overlap or match in name but not semantics, and decide what to do about them.

Re: REST Anti-patterns

#125

This misses the elephant in the room. The REST-inspired API that requires 10,000 API calls to do something that could be done in 1. This is a disaster from a simple performance perspective. There is no simple way to build transactions on top of REST so if you need to do something that involves updating more than one data record you really are best off updating them all in one API call. When you are writing a web fron…

>The REST-inspired API that requires 10,000 API calls to do something that could be done in 1.

That should be a non-issue. Consider search queries. They are a simple GET request that returns a collection of many results in one response. You can do the same, you just need to define collection resources or collection semantics for existing resources.

The only challenge is handling partial failures, like when you POST 1000 things, and 22 of them fail validation. So each thing needs a status code in the response and some unique ID so that you can find its status code in the response. (That is separate from the overall request status code.) I have the client send a UUID and the server responds with a collection keyed by that UUID so that it's easy to find, for each thing that you sent, what happened.

Re: REST Anti-patterns

#126

The initial and fundamental problem is a misapplication of REST. To take advantage of REST, you need some form of hypertext, not raw JSON APIs. Additionally, on a practical level, you need the end points to be relatively coarse grained, which can be achieved if you design the API for your UI use case, rather than general data access: http://intercoolerjs.org/2016/01/18/rescuing-rest.html Shoehorning HATEOS in JSON AP…

The issue with HATEOAS is a little overstated. You don't need a full AI with independent agency. What you need is a clear media type that corresponds to some domain concepts that both the client and server agree on. The client and server don't even have to totally agree, as long as there is some overlap. The server may provide functions that the client doesn't care about, and the client may care about functions that…

Without agency on the client side, supplied by humans, how is it advantageous to send an unknown number of potential actions from the server?

Re: REST Anti-patterns

#127
post #18
post #2

Why is POST /accounts/4402278/close correct in the first example? According to the rest of the post, PUT should be a better option. Closing an account seems to me like its updating a resource, not creating one. Also, will calling that url close the account multiple times? POST is not supposed to be idempotent

You may be operating under the misapprehension that "POST" means "CREATE". It WOULD make a nice set with CRUD operations: POST - Create GET - Read PUT - Update DELETE - Delete But that's not actually how the HTTP verbs are defined[1]. Instead, my own mental mapping looks something like this: GET - read information. Must be idempotent and side-effect free so this one really IS just for reading. DELETE- delete. Usually…

Agree with that. I was operating on the description in the blog post that, in my opinion, contradicts itself a little bit

Re: REST Anti-patterns

#128
post #103

Earlier quoted context omitted.

> Other commenters are correct that POST /accounts/4402278/close is not right (and also fairly hilariously contradicted in the next section). Of course its right. Read the POST spec. POST is for processing data. Its up to the server to what is processed how. If the POST is for closing a bank account, it is valid. I think, my bank would need verify a lot of things before I can close my account with a single click. So…

Just because a flag can be set with PUT doesn't mean the server has to accept it in all circumstances. Maybe there are preconditions elsewhere that must be met first, or maybe only someone with sufficient access credentials can set the flag. This plays pretty well with PUT. Again, this is the interface to a complex data model, and I would be wary of using a bank that dumped all of its security and process controls in…

A PUT means that the server accepts the payload as is. Yes, it can be restricted as is. But the request must be free of side effects. The server should not even validate the payload. And that also means that your request should not trigger stuff that cannot be triggered again. If your model _only_ relies on that flag, than the PUT is fine. But when I close a bank account, usually I trigger stuff on the server side (including validation). So a POST should be required.

Re: REST Anti-patterns

#129

This misses the elephant in the room. The REST-inspired API that requires 10,000 API calls to do something that could be done in 1. This is a disaster from a simple performance perspective. There is no simple way to build transactions on top of REST so if you need to do something that involves updating more than one data record you really are best off updating them all in one API call. When you are writing a web fron…

>The REST-inspired API that requires 10,000 API calls to do something that could be done in 1. That should be a non-issue. Consider search queries. They are a simple GET request that returns a collection of many results in one response. You can do the same, you just need to define collection resources or collection semantics for existing resources. The only challenge is handling partial failures, like when you POST 1…

on search queries, consider twitter search, I have read it is not REST because it is not idempotent

Re: REST Anti-patterns

#130
post #16

Other commenters are correct that POST /accounts/4402278/close is not right (and also fairly hilariously contradicted in the next section). Account status (open, closed, suspended, whatever else) is a property of the account, in the same way that the account owner's name is a property of the account. If you went to all the trouble to represent each account as its own resource, which I assume responds correctly otherw…

This depends on your data model. If "status" is just a property on the accounts resource and doesn't have further meaning, I would tend to agree with you. If "close" is an action or activity that acts upon an accounts resource, then his approach makes sense. Since the context is an account that we "need to close," I would assume the author is talking about something more complex than a database field. It's probably a…

Indeed—I would tend to argue that in most cases updating the value of an attribute on a resource for a complex operation is itself an antipattern.
Post reply on HN