Using code formatting for quoted text is not civil disobedience, it is an innocent mistake that should be gently pointed out and corrected.
Continuing to use code formatting after being made aware of the problem wouldn't be civil disobedience either. It would merely inconvenience the large number of people who read HN on mobile devices, for no purpose.
(Edited to remove a somewhat unrelated philosophical note.)
> Continuing to use code formatting after being made aware of the problem wouldn't be civil disobedience either. It would merely inconvenience the large number of people who read HN on mobile devices, for no purpose.
We all do it from time to time, even you did it few days ago [1], monospace have its purpose, maybe HN should simply fix it.
Oh come now. I used code formatting quite deliberately in that comment. I wanted to preserve the centering and single-spacing of the text on the back of the radio as best I could. The lines are short and render fine on a mobile device.
So yes, given HN's meager formatting options, monospaceisgood for that! :-)
You may note that later in that same comment there is a longer quote that I formatted in non-code italics.
But hey, if I encouraged you to create an HN account, that's great! Speaking as someone who writes code in a proportional font, we may have some interesting discussions ahead of us. ;-)
I propose using four underscores as a delimiter of a quote block, like asciidoctor, in addition to italics. I think it looks better than the markdown way of using ">" in front of a quote as it can get quite cumbersome and ugly when you're quoting multiple lines of something. However, I generally enjoy using markdown more if it works on a website. It just looks ugly IMO if it doesn't.
I’m rather young (on the border of Gen Y and Gen Z) so I guess I’m not old enough to have used either old Unix email or Usenet, so thank you for that tidbit.
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.
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.
That's right, that's the same issue. But in both cases, you can just send your list of items to fetch (respectively delete) in the body of the GET or DELETE request. (Because AFAIK, it's HTTP compliant to put a body in a GET request, even if it's rarely used).
Edit: I was wrong. It's allowed to put a body in a GET request, but it isn't OK to use it according to the HTTP spec (which admittedly kind of weird). Source: https://stackoverflow.com/a/983458
Edit2: according to an edit int the SO response, it looks like I wasn't actually wrong: or at least not since 2014 when these RFCs[1][2] became the standard for HTTP.
A body is and has always been syntactically permitted on any HTTP request.
However, it is semantic nonsense to put it on a DELETE or GET.
DELETE is defined to remove the resource identified by the URL; GET is defined to fetch the resource identified by the URL. There no purpose for an entity.
This is the point made in the SO answer I quoted, and this was the official position of the rfc2616[1], but as I said in my second edit, this rule was relaxed in the new version of the specification: rfc7231 published in 2014.
> The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI.
To :
> A payload within a GET request message has no defined semantics
Which, to me, sounds like: “it was forbidden to put info in the body, and now it's just not especially encouraged”. But maybe I'm over thinking the whole thing.
It doesn't really scale. There's a de-facto limit of 2,000 characters [0] in a URL. HTTP/1.1 is not opinionated about URL length, but practical implementations are.
If your ids are UUIDs, each has a length of 36. If your URL consisted of nothing but UUIDs, you could safely delete 55.5(repeating) of them.
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.
Having "create many", "update many", and "delete many" is three additional operations. Profusion may not be the word I'd use. Also, I will say they are very commonly requested operations, and they've lead to POST becoming overloaded in meaning.
Except now your server has to handle a lot more connections.
Was recently dealing with a list of 100+ simple text fields each with unique identifying meta info.
Most usage of the form would only involve updating a few at a time, but on initial entry or a large update all of them could be updated or deleted.
A RESTful approach would have me submit 100+ individual PUT requests. However for a smaller instance of our server it would likely be affected by 100s of requests at a time and it would significantly complicate the client code to make all of these requests at a time and do the error handling for it.
It’s actually a small payload, even with 100 items, so it’s ridiculous to send them individual in order to be “correct” if it
- leads to a worse user experience.
- increases load on the server.
- complicates the codebase.
Http2 has efficiency gains at the transport later but not typically at the application tier. Having a single http request lets you things like handling authentication, fetching common state (user object), etc a single time for a batch request. Http2 doesn’t help you here.
A lot of sites might have an HTTP/2 upstream server, but everything downstream is still communicating via HTTP/1.1. I would imagine you can only the benefits of HTTP/2 multiplexing if you fully utilize HTTP/2 end-to-end.
That means your CDN, your load balancers, and finally your actual applications-- any any other intermediaries -- all communicating via HTTP/2.
Not to say that HTTP/2 isn't the solution, but it's going to be slower than looking up "number of sites using HTTP/2", since you can't easily inspect the behavior of the intermediary servers.
What I mean is, typically, there are many layers between an end user's network request and reaching the server where it will be fulfilled. For example, you might have your site fronted by Cloudflare. They provide DDOS protection, etc. That Cloudflare server might accept HTTP/2 requests, and then open a new request to your load balancer server. Then, your load balancer opens another network request to the server fulfilling the request. The connections between these servers may only support HTTP/1.1. So you lose the benefits of HTTP/2 since you can't multiplex the network request end-to-end.
In this particular example (S3), I don't think this is really a concern.
Anyway, I'm curious... what components do you run into that don't support this yet? At least in your examples I can't think of any major players that don't do HTTP/2 out of the box, except, well, old versions.
Is this more of a hypothetical? In my experience HTTP/2 is pretty much ubiquitous for anything current.
The load balancer could append a header though with a session ID that is the same for the same HTTP/2 session, and then the server can batch based on the session ID and timeframe.
Have you ever heard the concept of the common antipattern of n+1 queries that the back-end developers try to avoid? What you are suggesting would create that pattern on the front-end too.
Yes, I understand the concept. I totally get that certain situations call for batching operations, including things that need to work transactional.
I think though that most operations don't need this. It's not an optimization I would blindly add to any operation, unless there's a specific case that warrants it.
I don't think that this is an anti-pattern. Most APIs do '1 thing at a time'.
The backend can batch deletes made in the same timeframe in the same HTTP/2 session, like how you can batch queries with Facebook Dataloader in GraphQL APIs to avoid the n+1 query problem.
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.
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.
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...
It's not an oversight in REST, it's one of the ways of trying to faithfully implement REST over HTTP, which has a gaping hole in the standard set of methods that messes with that use case. While HTTP (specifically 1.1) is an implementation of REST principles, that use case wasn't front-and-center at the time (PATCH is also a recent fix to another hole.)
There have been proposed standardized fixes such as generalizing the HTTP SEARCH method that first appeared in WebDAV[0], but none have yet gone far.
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.
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?
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.
This is before me being old enough to follow technology, so below is a good portion of conjecture and hearsay (I'd love to be corrected by someone who actually remembers it):
Tim Berners-Lee initial web browser was intended as an editing tool as well as a viewer, and these ideas came back when they went to write up HTTP as a a "proper" IETF standard. Not uncommon (bit less so today, but back then especially) to design specs with what they thought it should do, not what they'd tried/done in practice. Making an official spec is the chance to get this stuff in.
At some point, a bunch of the file-specific stuff was split off to WebDAV as an extra thing (work on that started 1996, HTTP 1.1 was finished 1997) - or rejected and WebDAV created as a new home for those ideas? But PUT among some others survived.
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.
I see things like <a> GET links for destructive operations all the time - are they in violation of the HTTP spec? Do browsers speculatively load these resources and delete things without the user interacting?
It’s definitely a problem. You should never have any destructive or modifying actions of any sort done from a GET request. In addition to browser prefetching, users might share a link without the receiving user realizing they are taking an action as soon as they click the link, which can be a source of security issues.
That being said, I too have seen things like this on the Internet. I would assume Google has some sort of heuristic to determine whether or not they can safely prefetch a link, but who really knows? You should absolutely avoid making this mistake in your own code.
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.
“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.
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.
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.
The client SDK exposes just the actual API and not the web API which is typically much more complex.
I really don’t want to worry about setting http headers to make an add-if-not-exists call for example. The API in a client library with a method “TryAdd(...)” is understandable as an API, and the setting of headers and 4XX code you might receive on a duplicate is just returned as false.
When this happens, it’s usually meant as a RPC endpoint, yes. However, it can be an abstraction, especially if you call it “POST /my-account/charges”, in plural form: you’re sending a new object to the “charges” resource (this architectural technique is usually called reification)
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.
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.
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".
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.
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.