{ "ok": false }
{ "ok": false }
wouldn’t that be more like
new Promise(() =>{ return { "ok": false }; })
{ "ok": "false" }
{ "ok": "no" }
{ "false": "ok" }
$false=true
{ "OK": "Ah ah ah, you didn't say the magic word." }
error = true with no description or answer is basically ten years of searching stackoverflow and reddit threads for an answer.
Or a link to a thread on microsoft answers that 404s
that’s the worst due to how microsoft answers redirects work making it impossible to go back to the previous page.
Honestly at this point if it’s source available it’s almost faster to dig through and find the affected module on source to determine behavior.
Unless of course it’s just crazy abstracted, which can be an unintentional form of obfuscation when applied poorly.
Aaagh! Getting some random old person flashbacks.
Kids. I r-remember a day… You won’t believe this… I got a 404 error page… It was otherwise a normal 404 page with a normal message on it, but it had a giant ad on it… like “while you’re here, how about you buy this stuff”… It was hell… You’ve got no idea how lucky you kids are with uBlock…
Please, please, please, PLEASE return error-codes and problem-details.
Here’s the RFC: https://www.rfc-editor.org/rfc/rfc9457.html
Nightmares.
It’s often valid to serve a 200 OK with an error in the application data.
How so?
Successful web request, web server functioning fine, application functioning fine, but the application needs to tell the user they have done something wrong in-app.
In my world for example there’s a piece of third party hardware I need to take a bunch of data from and deliver it to the user. One part of that data is telling the user there’s an error and they need to perform an IRL interaction with it to fix something, but the rest of the data and images in the payload are good
This looks so over-engineered. Most of the time you only need an error message. Make the message clear enough so that it can be shown to the end user.
Why even use HTTP, when you can just send bytes directly over the physical network card, right?
Because standards make it better for everyone. You’ve no idea when, who or in what context the error will happen or be received by.
It takes so little to return ProblemDetails, and improves the experience of devs using your API so much. Just do it. Stop thinking up edge cases and faffing about with excuses. Do it.
I think the challenge is that it looks like a lot of other ‘standards’ I’ve seen: on one hand tediously specific yet on the other hand, so open ended as to largely defeat the point.
Every problem must have a ‘type’. Ok, fine, so what are the semantics of the ‘problem type’? Well, nothing in particular, just has to be defined, but it might be nice if it’s a url telling a human about your own human thoughts on the type. Also, if you encounter multiple ‘errors’, you need to omit any that you arbitrarily fail to group into the same ‘type’ which shouldn’t be subjectively too vague either, so don’t think about making catch-all types so you don’t have to discard some of the errors.
You can’t count on the members, and a problem type may arbitrarily ‘extend’ to completely rearrange those members into members of child objects instead, but that’s really all up to the backend to decide however they want to arrange it, with no prescribed standard for error bundling, but an example of how a backend could voluntarily implement such bundling as an implementer specific extension if they like, but again, don’t bundle errors that shouldn’t seem to be of a common type…
Also I think it’s funny that they say do this in the name of being a good web citizen, but then say send this new mime type down, client’s Accept header value be damned.
It purports to drive toward “machine-readable” problems but it seems like there’s not much actually actionable and the client has to in practical terms do a bunch of bespoke handling to deal with a backend that is still pretty much open to do whatever they like.
It has a couple of reasonable seeming examples, but nothing that would make me think “Oh, you implement RFC 9457? Then I already have error handling code ready to go!”
I’ve seen all sorts of complex errors generated by backends that have all sorts of features like this and more (error messages with parameterized string values, json pointers to specific problematic pieces of the client request. However people just want a human readable response to pass along. I could imagine the example ‘pointer’ being useful to map error details to a client maintained form, but that’s not even the ‘standard’, just a random example ‘extension’…
Exactly! This is why the server should just send a clear error message. 99% of the time the client just wants to show the error message to the end user, and not have to wrangle all kinds of normalized data into one.
I wouldn’t even mind wrangling some normalized data, but it doesn’t seem very normalized in their examples.
Their first example suggests “great, there’s a human appropriate title and detail, and maybe this standard will say you should at least have those and they should be ready for pass through to a human operator”, with extensions providing room for more sophisticated behavior.
Then the second example, no more top level detail, now there’s an ‘errors’ array, and detail is under the children (which they don’t formally describe the concept of reparenting attributes, just incidentally showing it in an example of what an implementation could do with ‘extensions’). Well, at least I can still pass through the details if I find them and it will make sense right? “must be a positive integer”… Ok, nope, error information that requires the client to process a json pointer in order to manufacture some sort of actionable feedback. Again, this could be a neat optional feature, but a generic core client really has nothing they can bite into that generically applies to the standard.
The cited RFC I think is close to some ideas but softens it by trying to be open ended. If it specified mandatory top level “detail” member that is reasonably directly informative to a human operator without further processing, great, I know exactly where to find it even if I don’t otherwise understand your problem type. Mandate that errors may be a collection under an ‘errors’ list, but otherwise identical to top level? Cool. Saying that here’s some recommended members, but they are all optional and the behavior is really up to you, and you can just freely change everything you want and call it ‘extensions’… Just not prescriptive enough despite the long words…
Counter argument is that error codes and problem details can be used by attackers to reverse engineer and find exploitable parts of a system.
Within reason anyways
So can a 200 response with an error description
Yep, I’ve got one of these at work now. Technically, 200 can make sense here if you’re using HTTP as RPC transport, as the server relayed the request to its handler and returned the outcome, but damn if it’s not annoying to actually process the response.
I’ve also seen a lot of devs tie themselves into knots trying to map various execution types to the “semantically correct” HTTP code, but the thing is the abstraction of HTTP is not based around RPC and it’s ultimately a pretty weird fit that we’ve somehow come to view as normal.
Then just return a 500 - Server error. Nice and obscure.
The ability to separate “something wrong with what you sent” (4XX) and “something wrong on the server” (5XX) is very valuable in itself.
Yep
- 2xx - it’s good
- 3xx - not here cunt
- 4xx - you don fucked up
- 5xx - we fucked up, whatever you do aint changing shit.
1xx - We’re still working on it
And then there’s 418
The number of times I’ve gotten 5xx codes for bad requests is annoyingly high.
Fair. But they still fucked up so at least that’s on them
I guess it’s like a retail worker apologising excessively because of trauma.
It’s not us, it’s you
It’s us: 5xx
It’s you: 4xx
JSON API almost always means “not REST”. In other words, it works as intended.
how would you return metadata or more detailed error codes?
However you like, REST doesn’t dictate anything there. Just be consistent and use hypermedia.
JSON APIs almost never follow REST because they almost never use JSON as hypertext. Worse, no complete stable hypertext JSON standard exists. There’s JSON-HAL, but it lacks a way to represent resource templates (think HTML’s
<form>
).Therefore, with JSON APIs ignoring one of the most basic idea behind REST, why would anyone expect them to follow another idea of REST - consistency?
REST is a deceptively simple concept. Any time you build an HTML website a human can navigate without consulting documentation, you’re doing it better than vast majority of swagger documented corporate APIs.
returning a 400 never prevented me from adding more info to the response
The argument probably goes something like " if you adhere strictly to REST the error codes are all you need" and then metadata can be sent in response headers.
how should a REST API respond to the client sending a URL the ends in a string instead of a numeric ID? like api.social/users/ceeforayteen instead of api.socail/users/11037
I would do a 400 (Bad Request). Then, with varying amounts of detail depending on the scale of the project and the framework capability, the response body would be something like: { “error”:true, “reason”: “validation”, “detail”: “user id should be numeric” }
that’s what i would do too—a JSON response. or is that not what “JSON API” means?
A RESTful service is (usually as of today) a JSON API. They aren’t mutually exclusive things.
There’s no black and white definition there.
However, when someone is creating a RESTful service, they’re stating that they’ll be paying mind to HTTP Verbs and status codes as a fundamental part of their design.
In the original image posted, that dev clearly wasn’t paying mind to the HTTP layer and as such a commenter called it just a “JSON API”, which is the catchall, ugly, Wild West, typical way of doing things (always return 200, errors are in the json).
Once again tho, it’s not black and white. Others can and will disagree and want to be pedantic. I’ve been a professional dev for 35 years, devs love to argue abt this shit.
It’s still just another type of ID so you can do lookups on it. Nothing would change. UUIDs are used all the time.
Depends on the verb and the application. If the string is valid 200, if it isn’t 400, 404.
I don’t wanna be pedantic but most things we call REST aren’t REST. The original definition of REST is what we typically call HATEOAS. So when you say JAON API almost always means not REST you need to qualify that.
Congratulations! You failed.
no worries! a small failure is the first step on the way to a really really big failure.
Fun story close to a decade ago we were attempting to upgrade our batch scheduler called Tidal to version 6x which had a RESTful API.
One of the reasons we dropped the product was because we were getting 200 status codes meanwhile the output was a java dump of an error message.
They were adamant that this was an us problem, no matter how much I tried to explain to them with numerous links explaining to them that if something has a 200 status code that should mean things worked.
They argued that the 200 meant we were hitting the API fine. We would have to write code to read the return for if it was a error or not. I still don’t think they understood how stupid they were, even all these years later.
I have had that argument repeatedly with people. People insisting that HTTP error codes are “transport layer” and it’s “wrong” for an API to hijack them to report “application level issues”.
No, the whole point of “REST” was to map application semantics to HTTP in a way that actually normalizes some things like error handling and expectations around whether an operation could be expected to be idempotent and make the namespace navigable.
At one point my work announced a person who was an external hire to be the ‘API genius’ to set my company straight. He came from a super reputable well known company so of course he just the smart guy to fix our technical mess. He had sent a message saying that he had reviewed the teams API and concluded they were not restful. I had a glimmer of optimism, that someone recognized as authoritative would call the RPC style HTTP usage that always returned 200 and steer toward sanity, or at least honesty. No, his feedback was that was all fine, but REST does not use JSON, REST uses Protobuf, so they need to change to Protobuf to claim to be REST. Of all the what the hell I could have predicted, that one was not in my book…
To further your point and remembering my asinine discussions with the vendor.
Fine. I accept what they said. Then the return code should be a 5xx code not a 200.
I genuinely wonder if they addressed their fuckups.
Side note their updated desktop client (because of course new version didn’t have one so they had to write one fast) was a java client that needed 16gb of ram to run marginally well lol
The number of people talking about REST without having read the wikipedia page is astonishing. Roy Fielding’s dissertation on the subject might be of interest, but that’s from 2000 and absolutely not webscale.
(Edit: /s if that wasn’t immediately obvious)
It’s ok, as long as you make sure to use mongodb it will be webscale no matter what. But if you date use anything else, it won’t be.
GraphQL makes this same mistake
That’s true, but for a good reason. GraphQL is transport agnostic, so using HTTP status to represent errors doesn’t make sense. HTTP is just a carrier for GraphQL, and the status code represents whether or not the HTTP part was successful.
If only that were true. They are intimately connected and to pretend otherwise is laughable to me
What do you mean? You can literally run GraphQL without HTTP. This isn’t just a GraphQL-ism, gRPC also does it https://grpc.io/docs/guides/status-codes/
I understand that most people use GraphQL over HTTP and that from a developer perspective you’d rather have HTTP status codes like every other REST API. To which I’d say, why don’t you just use REST instead?
There are a bunch of legitimate reasons why a clean separation of transport layer and application layer makes sense - you just aren’t using them so it feels like an arbitrary frustration to you.
Have you ever run an application like a golang REST API behind an envoy or nginx proxy or load balancer and gotten an HTTP status 500 back and wrongly assumed it was coming from your application/golang code, only to later find it was a problem at the proxy or load balancer? If so, you’ve experienced the misdirection of combining transport and application layer being forced to share a status field. This isn’t a trivial example - time is wasted every day by developers misdiagnosing errors originating from transport as application errors, and vice versa.
You might not like it, but separating them IS smart design.
Logs, logs, logs, you’ll pour over logs anyway. Hands up anyone who has run GraphQL over anything but http? Won’t be many. And then another show of hands please: who’s written a basic request using http tooling instead? Bet there’s tons!
They threw away loads of tooling for the sake of vanity imo
Well no, the HTTP error codes are about the entire request, not just whether or not the actual header part was received and processed right.
Like HTTP 403, HTTP only has a basic form of authentication built in, anything else needs the server to handle it externally (e.g. via session cookies). It wouldn’t make sense to send “HTTP 200” in response to trying to access a resource without being logged in just because the request was well formed.
Many GraphQL and gRPC APIs do exactly that and return HTTP 200 even if the request didn’t auth.
Just because you are heavily biased toward using HTTP status for application layer errors doesn’t make it right.
Ehh, that really feel like “But other people do it wrong too” to me, half the 4xx error codes are application layer errors for example (404 ain’t a transport layer error, neither is 403, 415, 422 or 451)
It also complicates actually processing the request as you’ve got to duplicate error handling between “request failed” and “request succeeded but actually failed”. My local cinema actually hits that error where their web frontend expects the backend to return errors, but the backend lies and says everything was successful, and then certain things break in the UI.
frontend expects the backend to return errors, but the backend lies and says everything was successful, and then certain things break in the UI
That’s a double failure then: not only does the backend do it wrong, the frontend devs don’t even know it. If they’d agreed on one way of handling it, they’d still be able to work it out. But if the devs don’t even communicate their standards with each other and the frontend devs obviously don’t know about the problem…
Yep, their frontend used a shared caller that would return the parsed JSON response if the request was successful, and error otherwise. And then the code that called it would use the returned object directly.
So I assume that most of the backend did actually surface error codes via the HTTP layer, it was just this one endpoint that didn’t (Which then broke the client side code when it tried to access non-existent properties of the response object), because otherwise basic testing would have caught it.
That’s also another reason to use the HTTP codes, by storing the error in the response body you now need extra code between the function doing the API call and the function handling a successful result, to examine the body to see if there was actually an error, all based on an ad-hoc per-endpoint format.
So I assume that most of the backend did actually surface error codes via the HTTP layer, it was just this one endpoint that didn’t
How is this getting even worse still? Why would a single endpoint work differently? That suggests they have standards, just one arsehole decided to shit on it and the rest didn’t vet their code enough to catch the issue.
otherwise basic testing would have caught it
I worked QA in a small dev team for two years. You might be surprised how uncomfortable you can make some developers within five minutes of “basic testing”. By the time I left, the team lead loved me as much as some of the devs must have hated me.
Marketo my
belovedthe bane of my existence. Actually without a doubt the worst API I’ve ever worked with in my career. The response schemas are random and a 200 means nothing because it might also include a “success”: “false”". Our backend API is Python and we have strict typing rule but Marketo really makes that difficultAnother favorite is when the API barfs a stacktrace instead of valid JSON.
Removed by mod
Every time I see someone recommend this at work I die a little inside. Like… C’mon!