Live data from Hacker News

REST Anti-patterns

marcelo-cure.blogspot.com

21–30 of 133 posts

Re: REST Anti-patterns

#21
post #17

Earlier quoted context omitted.

Or, if you really want to be dogmatic, use DELETE when destroying something...in this case the customer account.

Closing it may not delete it, but simply mark it as closed.

In CRUD, delete is rarely a hard delete that removes the data entirely. Best practice in most situations is setting a flag to mark it deleted. Closing an account is the same behavior - you are not purging the data, rather setting it to a closed/deleted/archived state.

Re: REST Anti-patterns

#22
post #12
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

Because the action is designed to affect the /accounts/4402278 resource. Requiring a PUT here would (semantically) imply that /accounts/4402278 is a container that has various sub-resources. Also, there is nothing wrong with having an idempotent POST effect. "POST is not supposed to be idempotent" is not the same as "POST should never be idempotent". In this case, the POST acts on a boolean flag; it is harder to make…

I mean, we're running up against one of the problems which metadata systems have to deal with, which is that metadata about an object really "lives" in parallel with that object, and not really "contained within it". But usually you just think of an object as containing all of the metadata we know about it so far, and under that model this makes perfect sense.

To do this in 100% RESTful style you would therefore probably store details about how an account was closed in the /accounts/440278/closed reference, so a PUT is correct, with GET /accounts/440278/closed returning either a 404 for accounts which are not closed or else the metadata about how the account was closed. This could live in parallel with a cache that's on the resource itself describing whether it was closed or not.

So, POST or PUT, with the PUT exposing more of the metadata interface to REST and POST putting more of it in the request bodies themselves.

Re: REST Anti-patterns

#23
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…

The action is "close". The status may or may not be "closed", but that's not what he's doing. Read a little farther. In the brief example JSON for the accounts, there is no "status" property. In fact, there are four actions available on the account:

    {"rel": "deposit", href: "/account/4502278/deposit"},
    {"rel": "withdraw", href: "/account/4502278/withdraw"},
    {"rel": "transfer", href: "/account/4502278/transfer"},
    {"rel": "close", href: "/account/4502278/close"}

Re: REST Anti-patterns

#24
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 front end this is all the more acute because choreographing a complex interaction with a server is a PITA with asynchronous communications.

If Fielding's thesis went in the trash and got replaced with "one click, one API call, update the UI" we'd hear a lot less carping about how awful the web platform is.

Careful reading of the http spec is a road to hell anyway because 80% of it is dark corners that aren't really used or implemented.

Re: REST Anti-patterns

#25
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 workflow that initiates other actions and workflows, maybe even requiring additional review. I'd want to see/understand the requirements more fully before I started down either path.

Re: REST Anti-patterns

#26
post #11

What about error representation? Most of the time I find that actually representing errors is the hard part of creating a REST api. You usually want some representation of each field, plus maybe a generic one. I always have troubles with this. Is there a standard or a proper way to define/do this? I would be very interested.

If you are returning multiple errors of different types, (403 for the forbidden change and 422 for the incorrectly set field) then you are supposed to role it up into a generic 400. Google JSON API for more information about the right way to represent multiple errors at a time.

Re: REST Anti-patterns

#27
post #14

Nice to PATCH mentioned. Highly useful and often overlooked.

Yes. Just make sure everyone is on the same page for PATCH. Multiple ways to handle it, and two very different RFCs.

On an old project our backend team agreed to support PATCH, but they wanted it based on this RFC: https://tools.ietf.org/html/rfc6902

The front end team wanted something more like this (before it was ensconced in an RFC): https://tools.ietf.org/html/rfc7386

To me, RFC7386 more accurately represents the idea of just sending the updated content.

Re: REST Anti-patterns

#28
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…

I like to think of DELETE as "if the response to the DELETE is 200-level then further GETs to the resource should be at the 400-level." Call those responses to GET requests "2XXing" and "4XXing" respectively.

Similarly a PUT should make sense whether the underlying resource 4XXes or 2XXes, and should in either case make it 2XX with the same response.

Then POST is just a verb which does not share these semantics at all; POST can be done on a URL which either 4XXes or 2XXes, and even if the post succeeds that's no guarantee that the underlying URL will now exist. POST /update-caches for example might not change the HTTP statuses of anything.

Re: REST Anti-patterns

#29
post #9

Earlier quoted context omitted.

I don't think I would assume that "close" is the same as a delete.

Then why not cater for your own verb instead?

Because you should never, never, never create your own verbs.

The main reason APIs have become ubiquitous is that we have a shared understanding that follows us from API to API. That includes the concept of verbs, response codes, and how to interact with the nouns/resources. If you add verbs, you're breaking that agreement.

Also, from a technical perspective, some of the internet infrastructure - servers, routers, etc - drop things they don't recognize. Heroku for years was dropping the PATCH verb despite recommending its use for customers' APIs.. and PATCH is in one of the specifications! Imagine what would happen to your custom verb.

Don't create your own. Stick to the standards.

Re: REST Anti-patterns

#30

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…

There's nothing to stop someone putting resources on an api which do the one thing a client needs to do.

And what you describe nothing to do with REST, it's to do with overly fine-grained API design, without taking your users into account.

Post reply on HN