Readit News logoReadit News
jedberg · 6 years ago
Every single person writing a REST api should have to memorize this table:

GET - Return the current value of an object, is idempotent;

PUT - Replace an object, or create a named object, when applicable, is idempotent;

DELETE - Delete an object, is idempotent;

POST - Create a new object based on the data provided, or submit a command, NOT idempotent;

HEAD - Return metadata of an object for a GET response. Resources that support the GET method MAY support the HEAD method as well, is idempotent;

PATCH - Apply a partial update to an object, NOT idempotent;

OPTIONS - Get information about a request, is idempotent.

Most importantly, that PUT is idempotent.

Credit to arkadiytehgraet for retyping the table to be readable. Please give them an upvote for the effort.

arkadiytehgraet · 6 years ago
Every single person writing a comment on Hacker News should have to memorize this rule:

Never use code formatting for text, as it makes it unreadable on the mobile devices.

For my own (and others') convenience, here is unformatted rule table from parent comment:

GET - Return the current value of an object, is idempotent;

PUT - Replace an object, or create a named object, when applicable, is idempotent;

DELETE - Delete an object, is idempotent;

POST - Create a new object based on the data provided, or submit a command, NOT idempotent;

HEAD - Return metadata of an object for a GET response. Resources that support the GET method MAY support the HEAD method as well, is idempotent;

PATCH - Apply a partial update to an object, NOT idempotent;

OPTIONS - Get information about a request, is idempotent.

kevin_thibedeau · 6 years ago
> Never use code formatting for text

Until such time that the site supports quoted text a little civil disobedience is warranted. It's not like it's a hard problem.

Stratoscope · 6 years ago
Another rule to memorize: if one of the reasons for using code formatting is to preserve line breaks, simply add an extra blank line between paragraphs. Think of each line as its own paragraph. Then the text will be readable on any device.
jedberg · 6 years ago
As someone who mostly uses mobile, I agree with you, but in this case I couldn't figure out a way to make it readable without code formatting and without retyping it.

Thank you for the effort. I've updated my post with your text.

dgellow · 6 years ago
Expected caching behaviour is as important as idempotency IMHO, and too often ignored.
JMTQp8lwXL · 6 years ago
There should be an option for deleting many objects. For that, you have to do a POST request on AWS S3:

https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteOb...

Instead of polluting existing method names to mean new things, HTTP could offer more method names.

Having POST alternatively mean "send a command" makes it meaningless. The command could do anything.

paulddraper · 6 years ago
> There should be an option for deleting many objects.

What about fetching many objects or creating many objects or updating many objects?

jayd16 · 6 years ago
Seems like you could just use Delete with query params on the collection path. Is that not RESTful?

Deleted Comment

richardwhiuk · 6 years ago
PATCH on the collection.
kevin_thibedeau · 6 years ago
We don't need a profusion of operations in the core protocol. Do you need idempotence or not? Pick from one of these two things and elaborate on top of that.
felixfbecker · 6 years ago
If you don’t need it to be atomic, you can just make parallel requests. Should not be an issue with HTTP/2
treve · 6 years ago
What advantage is there to having a bulk operation vs many operations?

With HTTP2 you can send a ton of requests in parallel.

granshaw · 6 years ago
Careful with PATCH - some enterprises block PATCH requests (had some clients that did this)
sk5t · 6 years ago
I haven't yet encountered the horrible, deplorable organization that both MITMs its SSL traffic and filters on HTTP method--but I know it's out there, just waiting to ruin my day and diminish my faith in humanity.
twistedpair · 6 years ago
True. Some firewalls will add/remove headers as well. An easy way to lose a day debugging network traces.
rubber_duck · 6 years ago
I wondered recently - where do large queries fit in to this ? URL encoding has size limits and is inefficient - but you can't use get body
jedberg · 6 years ago
If you want to be purely restful, you'd POST your request with all the parameters, which would create a new query resource, and then return the query resource ID. You would then make a second GET request with just the query ID.

The GET would be cacheable because they query would be repeatable and idempotent. In theory you'd never have to make the POST more than once unless you are creating a new query, which would make a new ID.

sojournerc · 6 years ago
I use POST for complex queries for this reason. Some things aren't easily URI encoded. Easier to just post JSON. Not pure REST, but I'm not really seeking purity...
ben_jones · 6 years ago
Or complex nested queries, such as those frequently created in a CRM specifying many key value pairs with different comparators: =, >, <, !=, LIKE. Add complex sorting instructions, pagination instructions, etc.
pietrovismara · 6 years ago
Technically GET request allow a body in the HTTP spec if I remember correctly. It's just that most implementations don't support it.
pbreit · 6 years ago
GET and POST seem a ===lot=== easier.
chrisseaton · 6 years ago
How do any of these HTTP verbs interact with HTML? When you have a pure HTML site (no JavaScript) how do you use these HTTP verbs when all you have is <a> links?

For example, how do you have an up-vote link? What verb is that supposed to be? And links are all GET aren't they? Up-vote isn't idempotent. How do you make a correct up-vote link?

How do we have this disconnect between HTTP verbs and HTML? How did it work before AJAX?

(I'm not a web developer.)

lwf · 6 years ago
POST is effectively the catch-all verb. There's nothing that violates HTTP spec in having a site that only has one endpoint, `POST /`, that specifies the actual JTBD somewhere in the request body. It's simply nasty and unidomatic.

c.f. https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

User agents still don't support PUT et all in forms without JavaScript -- you're limited to GET/POST, c.f. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fo...

matthewmacleod · 6 years ago
You’d use forms with buttons in them, and style them to look however you like. I used to do this a lot when building pages using progressive enhancement; it’s less common now.

An “upvote” is probably an idempotent action. Calling an “upvote” endpoint moves an object into an “upvoted” state, regardless of what it’s previous state was. However, it’s probably semantically a PATCH, since it’s a partial update of a resource.

There is no real disconnect here.

jkeuhlen · 6 years ago
You can have buttons and forms with pure HTML. Sure links are all GET requests, but you can specify the method of a form.
gkoberger · 6 years ago
I agree REST APIs should be built this way, however I disagree any end user should ever have to think about APIs this way. I think a good SDK should hide most of this complexity away, and no real human should ever have to know the difference between a PUT or a POST. APIs should think more like people; people shouldn't have to think more like APIs.

EDIT: Since I didn't make my case well enough, here's an example. Let's say you want to charge a credit card. Are you doing a `POST /charge`? Or would it be better to say `card.charge(500)`? My point isn't that there shouldn't be a proper REST API below it, but rather that we should offer abstractions so normal semi-technical people can use APIs and don't have to think too much like a computer.

travisjungroth · 6 years ago
“SDK” is a much less useful hard boundary than “Web API” for where I stop providing service. Should I provide an SDK in every language a client might use? If they want to access my service in a language I don’t support, should I tell them to piss off? I could offer for them to just hit the API themselves, but then we’re back where we started.

On the other hand, if I offer a web service and some someone asks “but what if I can’t make HTTP requests?” I’m _perfectly_ happy to tell them to piss off.

kevin_thibedeau · 6 years ago
A human should know because it affects user agent behavior. Over use of POST where it is not needed causes pointless friction with confirmation dialogs that could be avoided with PUT.
mattlutze · 6 years ago
I feel like, if we're not writing data-interfacing applications with PUT and POST as specifically different actions in mind, we're doing something wrong.

People think in ambiguity; adding a new item or replacing an existing item, as in this example, shouldn't be something an application needs to guess at.

jmull · 6 years ago
How could someone use an API correctly without understanding it?
rswail · 6 years ago
People have being using banks for centuries.

POST /my-account/charge is not an abstraction, it's pretty much exactly what people do and have done.

thecleaner · 6 years ago
What is the problem that such codes solves ? Why cant it just be json with a POST request with a field specifying the operation ?
bradleyjg · 6 years ago
You can always do your own custom thing, but you give up on leveraging anything that anyone has written and anyone trying to implement your thing has to figure out what’s going on from scratch instead of being able to understand it as a variation of something s/he has seen many times before.
_tkzm · 6 years ago
that is true. people overcomplicate things. but i went the other way, because the number of articles about how people get rest wrong is staggering, so all my api calls are post requests no matther what. what matters is the rpc method being invoked and i truly don't care if someone cannot use plain web browser to perform requests. thats what documentation and api client is for. i have spoken. this is the way.
rswail · 6 years ago
I'm glad you haven't described your API as RESTful.

You're perfectly fine to design an API around RPC calls and POST. There are all of the issues around RPC that you will have to deal with (long running operations, versioning, serde and marshalling of arguments, argument and response typing and interface definitions, codegen of the IDL to product client and server stubs that will require modification and back/forward porting of implementation).

But an API definition like this one, covers a lot of that as part of the protocol, most of which is defined by HTTP anyway. You also get encryption, compression, caching, tooling "for free".

fyp · 6 years ago
You can make anything idempotent if you add a "If-Match" header that returns a 409/412 if the current resource version doesn't match. Not only does this prevent the same request from being applied multiple times, it prevents losing updates when multiple different requests are submitted at the same time. Google cloud storage has a good example of this: https://cloud.google.com/storage/docs/generations-preconditi...

The only exception is on resource creation (POST) since there's no existing version/generation number to match on. You can get around that by letting the client generate the id with a random id and reject if the id already exists. I haven't decided if this is a good idea or not since the client can potentially choose really weird vanity ids (especially if you're using uuid in hex or base64). But if you don't expose your internal ids in any UI that seems fine too.

littlecranky67 · 6 years ago
I've designed quite some REST APIs, but I've come to the conclusion that all those semantic/HATEOS or other REST guidelines don't always apply or make sense, depending on the problem domain.

I worked in finance and designed a REST API, and besides the standard user/account object, basically ALL the data and operations were neither idempotent, cacheable, durable and often couldn't possible be designed using HATEOS et al.

Quotes, orders, offers and transactions carry lots of monetary amounts which are sent in user currency, which is auto-converted depending on the user requesting it (and currency conversion rates is part of the business). Most offers are only valid a limited amount of time (seconds to minutes) because of changing market rates. There is also no "changing" of object as in PATCH/DELETE, all you do is trigger operations via the API and every action you ever did is kept in a log (regulatory wise, but also to display for the end user).

There is some way to try to hammer this thing to fit with HATEOS et. al. and I put some effort in it, but I would have ended up splitting DTOs into idempotent/mutable and non-idempotent/mutable parts and spread them across different services, bloat the DTOs themselves (i.e. include all available currencies in a quote/offer) and have the validity/expiry of objects via HTTP caching (instead of the DTOs). That would have ended up in a complex and hard-to-read API, would have significantly worse performance (due to lot of unneeded data & calculations) and some insane design decisions (like keeping expired offers/quotes around just so they are still available at their service URL with an id, even though the business requirements would never store expired offers).

Sometimes you just need to use your own head, accept that the problem domain might not be covered by other "guidelines", and come up with a sane design yourself.

pas · 6 years ago
REST shines where there is a big path dependent interaction graph - ie. feature switches, permissions, plans/packages and other statefull stuff.
SSchick · 6 years ago
At MS, in our team no manager gave the slightest damn about being restful or any proper consistent API design. Everything was constantly rushed and just 'tacked on', random API versions were created, contracts were broken, nothing was consistent. It was a mess. That said, I believe most of these guidelines completely ignored in most teams.
cellularmitosis · 6 years ago
Grammar nit: "That said," is usually followed by a contradictory statement, not a supporting statement. i.e. "That said, most folks outside of my team follow these guidelines".
TinyRick · 6 years ago
As a fairly heavy consumer of the Azure DevOps REST APIs, this sounds pretty accurate.
JMTQp8lwXL · 6 years ago
There are many actually RESTful APIs out there. Some even have good documentation to accompany. I've heard Stripe given as an example that's especially notable.

Managers will care if your API's are a contract with your end customer (e.g., your product is providing APIs), and you're watching your NPS scores.

dpark · 6 years ago
It’s almost as if there are different groups in Microsoft with different priorities. Why is it so hard to get 130k people in complete assignment across all areas? Seems like a simple problem.
Someone1234 · 6 years ago
> It’s almost as if there are different groups in Microsoft with different priorities. Why is it so hard to get 130k people in complete alignment across all areas? Seems like a simple problem.

I feel like this could have been said without the sarcasm and it would have been a great discussion starter. Instead a potentially valid point/retort will be obscured by the tone and discussion surrounding it.

For example:

> Unfortunately large organizations often struggle to get groups into alignment on issues like this, unless there's a strong mandate from the top down (e.g. Amazon).

No sarcasm or snark, same basic substance.

vearwhershuh · 6 years ago
The primary innovation in REST is HATEOAS (which isn't mentioned in the document at all.) JSON isn't a hypertext, it just isn't a good format for REST-ful services.

http://intercoolerjs.org/2016/01/18/rescuing-rest.html

http://intercoolerjs.org/2016/05/08/hatoeas-is-for-humans.ht...

Doesn't anyone notice this? I feel like I'm taking crazy pills.

https://www.youtube.com/watch?v=HOK6mE7sdvs

clintonb · 6 years ago
The trouble with HATEOAS is that it requires extra work on the client. The client is supposed to start at the root of the API, request URLs, and cache them. Getting the data one wants requires multiple HTTP calls, many of which are supposed to be cached.

I tried implementing this and found it toilsome. It was far easier to use versioned URLs that followed a documented pattern.

When I checked about three years ago there wasn’t much in the open source community that I could build atop for clients. I also didn’t want to maintain an SDK client in addition to the API itself.

sk5t · 6 years ago
"Toilsome" is probably the most kindly yet still accurate thing one could say about exposing HATEOAS to the real world, at this particular point in time.
vearwhershuh · 6 years ago
It's all a category error. HATEOAS was descriptive, he was describing the early web architecture, and it was implemented without thinking about it in web 1.0 apps.

It only became problematic when we tried to shoe-horn it into traditional data APIs.

ben509 · 6 years ago
So that's what HATEOAS is. I had been wondering why the Github APIs had these absurdly large responses with a shit-ton of urls.

> JSON isn't a hypertext, it just isn't a good format for REST-ful services.

The point of REST was to take ideas from the browser and apply them to other services.

But HATEOAS is proving that REST only really makes sense if you've got a browser on the other end.

> Doesn't anyone notice this? I feel like I'm taking crazy pills.

The first comment I saw on this article was, _every single person writing a REST api should have to memorize this table_.

If you were trying to sell people on a new library and said, "everyone here has to memorize this table," you'd get laughed at as a crazy person.

ssijak · 6 years ago
No, HATEOAS is not for humans but was imagined for api consumers. All those links that you mentioned in the Github api responses are named and you as a client can use them, where the actual url can change. Also, you as an api consumer can know what actions are available.

That being said, I have never seen developing api client driven mainly by HATEOAS

mumblemumble · 6 years ago
Every time I see a discussion about REST guidelines, I get a little bit more happy about having switched to gRPC.
asdkhadsj · 6 years ago
Man, I wanted to love gRPC. The disconnect between Protobufs and languages just felt too great though. You could do some weird things that just made every language feel, to some degree, non-idiomatic.

I switched to Twirp at one point to retain the simplicity of RPC + Protobuf, but avoid some of the complexity we didn't need via gRPC... but even that suffered, of course, from the Protobuf problem.

Finally I'm back to plain HTTP and JSON. We don't worry too much about REST fundamentals, and honestly we're more like an ad-hoc (JSON) RPC over HTTP, but it's simple.

The only problem is documentation. The one thing that I found perfect with Protobuf. Seems really hard to have everything here.

addcn · 6 years ago
How would you articulate "the protobuf problem" to a gRPC novice like me?

Also re http/rest docs -- check out my open source project -- it's sort of like Git but for Rest APIs https://github.com/opticdev/optic

ben509 · 6 years ago
> You could do some weird things that just made every language feel, to some degree, non-idiomatic.

Could you elaborate on this?

jayd16 · 6 years ago
The load balancing still seems like a headache for gRPC. What do you use?
nine_k · 6 years ago
Envoy proxy seems to solve it reasonably.
danellis · 6 years ago
Why isn't this called "HTTP API Guidelines"? It doesn't seem to have much to do with REST at all. For example, it says that people should be able to construct URLs, whereas the REST style uses the URLs found in resources.

To be clear, I'm not saying that there is anything wrong with the practices they propose here, just that they're not what they're claiming they are.

dang · 6 years ago
erjjones · 6 years ago
Ideally, they wouldn't re-invent the wheel again and just stick with the ODATA protocol. They already have the platform to do so - https://docs.microsoft.com/en-us/odata/resources/roadmap