Oh no… this brings back memories LOL
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.
Please, please, please, PLEASE return error-codes and problem-details.
Here’s the RFC: https://www.rfc-editor.org/rfc/rfc9457.html
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
Nightmares.
It’s often valid to serve a 200 OK with an error in the application data.
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.
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
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…
{ "ok": false }
{ "ok": false }
wouldn’t that be more like
new Promise(() =>{ return { "ok": false }; })
{ "ok": "false" }
{ "false": "ok" }
$false=true
{ "ok": "no" }
{ "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.
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.
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.
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.
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.
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.
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.
Depends on the verb and the application. If the string is valid 200, if it isn’t 400, 404.
It’s still just another type of ID so you can do lookups on it. Nothing would change. UUIDs are used all the time.
returning a 400 never prevented me from adding more info to the response
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.
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. It is so wildly common that people can’t imagine it working another way, and I get that.
But it’s not “wrong” to do application layer auth status codes and apply no transport layer auth status codes It’s just a different paradigm than most devs are used to.
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.
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
Congratulations! You failed.
no worries! a small failure is the first step on the way to a really really big failure.
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 difficultEvery time I see someone recommend this at work I die a little inside. Like… C’mon!
Another favorite is when the API barfs a stacktrace instead of valid JSON.