top | item 32082082

(no title)

vasilakisfil | 3 years ago

> Returning a 2xx code immediately tells the client that the HTTP response contains a payload that they can parse to determine the outcome of the business/domain request.

There is nothing in the protocol that mandates only 2xx status codes are parsable. Instead, the Content-Type pinpoints to the client what kind of content the body has, regardless the status code. And the content-type will most probably be what the client asked (if not, then the server announces that the response content is not subject to negotiation, something that you see rarely nowadays..)

In general I think this post reflects one of the mentalities that appeared around 10 years ago regarding HTTP APIs (another was the extreme hypermedia-driven APIs). But I really think nowadays we can do much better, we can deliver a practical API that works 99% of the times.

By the way in the latest HTTP RFC (RFC9110) status code 422 is finally officially defined (previously was part of webdav extention), which means that the war 422 vs 400 for validation and other semantic errors is over and we have a clear winner. But 200 vs 404 for something that was not found? Well that was has ended long ago I think..

discuss

order

conductr|3 years ago

I think 404 being a common and useful server error is the issue. Had they/REST aligned on 204 No Content (for things like the employees/100 example) or something 2xx and less common I think it wouldn’t be much of an issue at all. I still think it’s actually not much of an issue. Of all the quirks out there, this creates little pain

dragonwriter|3 years ago

> Had they/REST aligned on 204 No Content (for things like the employees/100 example)

Who is “they/REST”, and where have “they/REST” aligned on anything. All REST says is “use the underlying protocol without messing with its semantics, but only the parts that correspond to REST semantics”.

If the resource exists and is accurately represented by no data, then 204 fits for a gET, but that’s a different case than where there is no matching resource to the URL. 204 is mostly for modifying actions (e.g., PUT, DELETE) that don’t need to return more than the fact of success.

firebird84|3 years ago

I've never seen a response indicating the content is not subject to negotiation. I generally only see that the response is not acceptable (i.e. the client has indicated they can't accept it) and the server skips processing the request.

oliwarner|3 years ago

> There is nothing in the protocol that mandates only 2xx status codes are parsable

I think a kinder reading of this point is "a 2xx response means you can parse the thing you were expecting to parse"

zenexer|3 years ago

That should be indicated by the Content-Type header, not the status code. If you get a 2XX response but the Content-Type isn't what you expect, you probably shouldn't try to parse it. I've seen misbehaving APIs return 2XX when they really should've returned 503.

Often this it to get around the inability for some cloud-based load balancers to accept 5XX status codes as healthy responses. Take AWS ELB/ALB, for example. There are conditions under which a target instance knows the underlying issue isn't related to its own health, such as during planned maintenance, upgrades, or database failures. In these situations, it would be desirable to return 503 and configure ELB/ALB to accept that as a healthy response. Since AWS won't let you do that, some applications will just return an empty or bogus 200 response during upgrades or maintenance.

dragonwriter|3 years ago

> I think a kinder reading of this point is “a 2xx response means you can parse the thing you were expecting to parse”

It doesn’t though.

Even with an Accept header on the request, it is not impermissible for a server to return a 2xx result with a different format indicated by the Content-Type header if it cannot, for whatever reason, return a result in a requested format (it may also, consistent with the HTTP spec, return a 406 Not Acceptable or, if it wants to be cagey about a resource representation existing if there is none matching the Accept header, 404 instead.)

If you want to know whether and how you can safely parse the response, the HTTP compliant way is to read the Content-Type header. Otherwise, you are relying on assumptions (which may be valid for out-of-band, non-HTTP reasons) about behavior that are outside of the spec.

agloeregrets|3 years ago

This is a whole lot of nice sounding theory but ultimately in practice this is just a downright mess to handle in a real application calling the API. If you are using the Angular httpClient for example, a 404 immediately throws an observable error when your app really should be telling the user that there are no results for that query. This crosswires a potential server-level error (broken routing etc) with a request level error in error handling and would make it way harder to determine the cause of the error and lead a dev to just write `status.code ==="404" ? 'User does not exist': ....`

Did I mention that httpClient, by default, doesn't let you get 404 error bodies?

But ultimately, it is all just ideas on 'how neat it would it be to use codes!' when in practice it is so so much better to just drop it and use the codes for more literal values. Imagining a users/{X} as a 404 for invalid 'X' is fun..but like..the server actually defines it as something like /users/:userId and it isn't actually an invalid route and will not be caught by the default 404 handling. It's a conceptual dance.

SahAssar|3 years ago

> Did I mention that httpClient, by default, doesn't let you get 404 error bodies?

Why would a http client not let you get http response bodies for statuses that usually send bodies? I could understand it for a 201, and definitely for a 204, but for a 404 it just seems like bad design of the client.

dragonwriter|3 years ago

What I am hearing is “Angular httpClient is badly defined”, which is the kind of risk you run into a lot with big monolithic highly-opinionated frameworks.

nrdvana|3 years ago

jQuery gives you the body. ExtJS gives you the body. Webix gives you the body. Maybe this is an Angular problem?

dariusj18|3 years ago

Don't get me started on HTTP 300 support

zinekeller|3 years ago

> By the way in the latest HTTP RFC (RFC9110) status code 422 is finally officially defined (previously was part of webdav extention), which means that the war 422 vs 400 for validation and other semantic errors is over and we have a clear winner.

Unfortunately, the way 422 is written implies that the sent body/content has error(s) and not the header. It's close, but I still feel that for GET requests it's wrong.

bbatha|3 years ago

The standard says nothing about bodies:

> The 422 (Unprocessable Entity) status code means the server understands the content type of the request entity (hence a 415(Unsupported Media Type) status code is inappropriate), and the syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions. For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.

https://datatracker.ietf.org/doc/html/rfc4918#section-11.2

Additionally, bodies are allowed on GET requests by the standard though are not commonly used because of bad middleboxes. However, many GET requests include query params or other parts of the url to be parsed, and its completely reasonable interpretation of the standard to return 422 if those are not well-formed according to application rules.

shadowgovt|3 years ago

There's nothing in the protocol, but in general, you should not assume non-2xx status codes have parseable payloads (more specifically, you should not assume the format of a non-200 status code).

Reason being that any intermediary step in the chain of resolving your request can return the response. If your load balancer has fallen over? You'll get a 500 with a plaintext body. Don't parse that as JSON.

(Technically, any intermediary step might also return you a 2xx with a non-parseable body, but that scenario is far, far more rare... Mostly see it in completely misconfigured servers where instead of getting the service you're trying to talk to you get the general "Set up your site" landing page).

zeveb|3 years ago

> you should not assume the format of a non-200 status code

You should never assume format based on status code at all! You should detect it based on the Content-Type header.

> You'll get a 500 with a plaintext body. Don't parse that as JSON.

Any intermediary which returns plain text with an application/json Content-Type is badly, badly broken.

dragonwriter|3 years ago

> There’s nothing in the protocol, but in general, you should not assume non-2xx status codes have parseable payloads (more specifically, you should not assume the format of a non-200 status code).

There’s absolutely something in the protocol, and you should absolutely use the Content-Type header to determine whether there is a body and whether it is in a parseable format irrespective of the status code, except for the minority of status codes defined as not having a body (e.g., 204 & 205.)

Spivak|3 years ago

> There is nothing in the protocol that mandates only 2xx status codes are parsable.

I think my overly defensive view of this for real-life code is that error states are inherently situations where the normal code contracts break down and that I must make fewer assumptions about the response, for example that they are well-formed or even match the requested content-type.

The number of times that I've encountered a JSON API that can suddenly return HTML during error states or outages is too damn high. So unless you give me a 2xx I'm not going to assume I got something intelligible.

eadmund|3 years ago

> I must make fewer assumptions about the response, for example that they are well-formed or even match the requested content-type.

I think that you should always assume that an HTTP response is a well-formed HTTP response (otherwise you can't even trust that the 404 itself is correct); and you should never assume that the received MIME type is the same as the ones you indicated you accepted; you should always check the Content-type header.

wizofaus|3 years ago

I'd say most web APIs I've used or developed recently return JSON even with 4xx or 5xx error codes. What can be annoying is knowing what JSON schema to parse with depending on the status code, as not even the Content-Type header will tell you that. APIs (esp. those behind load balancers) that sometimes return HTML and sometimes JSON are far too common though - the problem there is that the JSON responses are appropriate for programmatic consumption (terse/semantically well defined) where HTML ones typically aren't. But even if the Content-Type header is abused (application/octet-stream anyone?) it's not hard to write code that copes with either. One API I used recently returned JSON in some cases and CSV format in others, with no distinction between status code OR content type!