5 ms·
Honestly, my controversial take is that for APIs, it would be cleaner to not use any HTTP status codes other than 200 and have all of the semantics in the body
by saghm 2y ago
Honestly, my controversial take is that for APIs, it would be cleaner to not use any HTTP status codes other than 200 and have all of the semantics in the body of the response. I'm sure someone smarter than me will jump in and explain why this wouldn't work in practice, but it just feels like application semantics are leaking from a much more natural location in the body of the response. I feel similarly about HTTP request methods other than POST in APIs; between the endpoint route and the body, there should be more than enough room to express the difference between POST, PATCH, and DELETE without needing them to be encoded as separate HTTP methods.
- evnix 2y agoThis is the way to go, pretty much solves, 404 resource not found or route not found. But you will get laughed at by so called architectural dogmatists. Remember we aren't really doing REST, it's just RPC and let's call it that. Shoehorning http protocols error codes as application error codes, drinking the cool aid and calling it best practice is beyond bizzare.
- marcus_holmes 2y agoAgree. "200 - successfully failed to do the thing" is valid and useful. 500 is "failed to do anything at all"
- tayo42 2y agoYour kind of describing things like thrift and other rpc servers?
- saghm 2y agoPossibly. I'm not sure why it should require switching to an entirely different protocol though; my point is that making an API that only uses POST and always returns 200 is something that already works in HTTP though, and I have trouble understanding why that isn't enough for pretty much everything.
- tayo42 2y agoYou need some kind of structured way to describe the action to take, what the result is or what the error is. so the client and server can actually parse the data. that's the protocol, whether its something formal like rpc libraries, or "REST"-ish or w/e json-rpc is probably what your describing over http, maybe if you squint enough graphql too
- lll-o-lll 2y agoYou are thinking like a developer, but there is a world of networking as well. Between your client and server will be various bits of hardware that cannot speak the language you invent. 200, 401, 500 — these are not for the use of the application developer — but rather the infrastructure engineer.
- necovek 2y agoYou lose some benefits of features already implemented by existing HTTP clients (caching, redirection, authorization and authentication, cross-origin protections, understanding the nature of the error to know that this request has failed and you need to try another one...). It's is certainly not comprehensive, but it's right there and it works. Moving to your own solution means that you have to reimplement all of this in every client.
- Joker_vD 2y ago> understanding the nature of the error to know that this request has failed and you need to try another one... Please elaborate. In my experience, most of HTTP client libraries do not automatically retry any requests, and thank goodness for that since they don't, and can't, know whether such retries are safe or even needed. > redirection An example of service where, at the higher business logic level, it makes sense to force the underlying HTTP transport level to emit a 301/302 response, would be appreciated. In my experience, this stuff is usually handled in the load-balancing proxy before the actual service, so it's similar to QoS and network management stuff: the application does not care about it, it just uses TCP.
- 2y ago
- omcnoe 2y agoThere are a lot of useful network monitoring tools that can analyze HTTP response codes out of the box. They can't do this for your custom application error format. You don't have to go crazy with it, but supporting at least 200/400/500 makes it so much easier to monitor the health of your services.
- bilbo-b-baggins 2y agoGo ahead try to implement something like cross-origin requests or multipart encoded form uploads just using the body semantics you described. I’ll wait. Also that is not a controversial take. It is at best a naive or inexperienced take.
- saghm 2y agoBoth of those happen in the context of web browsing rather than existing in APIs in a vaccuum; I'd argue that there's absolutely no reason why the mechanism used to request a webpage from a browser needed to be identical to the mechanism used for the webpage to perform those actions dynamically, which is pretty much my whole point: it doesn't seem obvious to me that it's useful to encode all of that information in an API that isn't also being used to serve webpages. If you are serving webpages, then it makes sense to use semantics that help with that, but I can't imagine I'm the only one who's had to deal with bikeshedding around this sort of thing in APIs that literally only are used for backends.
- yxhuvud 2y agoMultipart messages definitely happens in APIs as well, if you are handling blobs that are potentially pretty big.
- turbojet1321 2y agoI'm sympathetic, but this can have issues if you want your API to be used by anything other than your own client, including stuff like logging middleware. A lot of tools inherently support/understand HTTP status codes, so building on top of that can make integration a lot easier. We, very roughly, do it like this: - 200: all good - 401: we don't know who you are - 403: you're not allowed to do that - 400: something's wrong and you can fix it - 500: something's wrong and you can't fix it Each response (other than 401) includes a json blob with details that our UI can do something with, but any other consumer of the API or HTTP traffic still knows roughly what's going on. I've worked in places where we really sweated on getting the perfect HTTP status codes, and I'm not sure it added much benefit. On POST - I find myself doing logical GETs with POST a lot, because the endpoint requires more information than can be conveyed in URL params. It makes me feel dirty, and it's obviously not RESTful but you know - sometimes you just have to get things done.
- brabel 2y agoYou've just described basically everything a dev needs to know to implement HTTP APIs that report status codes properly, yet some people still seem to think it's oh so complicated. What has gone wrong?
- turbojet1321 2y agoI can understand how people might look at all the full list status codes and think it's all too hard, but yes, once you realize that there are only a handful you need most of the time it all becomes pretty simple.
- saghm 2y agoSure, but the problem in my opinion is that while the handful that you pick is totally reasonable, someone else might pick a slightly different handful that's just as reasonable. If I want to use a new API and delete a user, how do I know if it uses DELETE or POST, and if it will return 401 or 403? At best, you'll be able to skim through the documentation more quickly due to having encountered similar conventions before, but nothing stops that from happening in terms of request and response bodies either. The fact that existing tooling relies on some of these conventions is probably a good enough reason to do things this way, but it's not obvious to me that this is because it's actually better rather than inertia. Conventions could be developed around the body of requests as well, and at least to me, it doesn't seem obvious that the amount of information conveyed at the HTTP method/response status layer was necessary to try to separate from the semantics of the request and response bodies. I'm sure that a part of that was due to HTTP supporting different content types for payloads, but nowadays it seems like quite a lot of the common alternatives to JSON APIs were designed not to even use HTTP (GraphQL, gRPC, etc.), which I'd argue is evidence that HTTP isn't necessarily being used as well for APIs as some people would like. To make something explicit that I've been alluding to, everything I've said is about using APIs in HTTP, not HTTP in the context of viewing webpages in a browser. It really seems like a lot of the complications in HTTP are due to it trying to be sufficient for both browsers and APIs, and in my opinion this comes mostly at the expense of the latter.
- lmm 2y agoYeah, that's usually the pragmatic thing to do. Facebook does that with their API, for example. 4xx or 5xx gets you the default HTTP handling for that kind of error. Occasionally - especially in small examples - that default handling does what you want and saves you duplicating a lot of work. More often it gets in your way. I'd compare it to browser default styling - in small examples it sounds useful, but in a decent-sized site you just end up having to do a "CSS reset" to get it out of the way before you do your styling.
- JodieBenitez 2y ago> Honestly, my controversial take is that for APIs, it would be cleaner to not use any HTTP status codes other than 200 and have all of the semantics in the body of the response. We've been doing that for 20 years with json-rpc 1.0 --> { "method": "echo", "params": ["Hello JSON-RPC"], "id":1} <-- { "result": "Hello JSON-RPC", "error": null, "id": 1} In this context, HTTP is just the transport and HTTP errors are only transport errors. Yes, you throw away lots of HTTP goodies with that, but there are many situations where it makes more sense than some half-assed ReSTish API. YMMV.
- LouisSayers 2y agoI like to find a middle ground. I use http status codes to encode how the _request_ was handled, not necessarily the data within the request. A 400 if you send mangled JSON, but a 200 if the request was valid but does not pass business validation rules. Inside the 200 response is structured JSON that also has a status that is relevant at the application level. Otherwise how can for example you tell if a 404 response is because the endpoint doesn't exist, or because the item requested at the endpoint doesn't exist? I believe it's important to have a separation between what is happening at the API level vs Application, and this approach caters for both.
- bvrmn 2y ago> A 400 if you send mangled JSON, but a 200 if the request was valid but does not pass business validation rules. What about empty required field in JSON? Is it still mangled or it's already BL?
- LouisSayers 2y agoAs it's not to do with the http request and the body was able to be parsed, in my book that'd be classified as being at the application level, so results in a 200 status with a JSON response detailing the issue 200 OK {status: "failed", errors: ["field X is required"]} How you deal with this on the application side, what JSON statuses you have etc is up to you.
- bvrmn 2y agoIt's an client error and it's highly beneficial to make it 400 for monitoring purposes. You want to see your FE or mobile devs deployed a faulty app.
- LouisSayers 2y agoThat depends on how you set up and do your monitoring. Not every failure needs to be indicated by an HTTP status code. For example, on a server I'm working on there are helper functions that generate different types of responses. Responding in certain ways will produce a 200, but will also log a warning or error. On the client side, you can create request helpers that all requests go through and that can resolve requests appropriately, rendering error messages to the user etc. The main thing is to have a well defined, consistent approach.
- kdmtctl 2y agoAnecdotally the color codes make life much easier when debugging a new API. You instantly see that's something is wrong. If everything is green you don't realize that something is wrong until you carefully read a uniquely structured custom response. Saves a lot of effort.
- int_19h 2y agoOne reason for using HTTP verbs is to distinguish between queries and updates, and for the latter, between idempotent and non-idempotent updates. This in turn makes it possible to do things like automatically retry queries on network errors or cache responses where it is safe to do so.