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” just because it isn’t the way it’s historically been done.
Think the point would be that it’s super easy to also set a ‘non-ok’ status in HTTP. Sure it may be insufficient for sophisticated handling, but at least you can get a vague sense of ‘something went wrong’…
Sure have your more specific API specific error code and your error details in the body, but at least toss a generic ‘500’ into the status code. I often find myself writing client software where I don’t need specific handling I just need to know ‘it failed’, and it’s obnoxious to deal with these interfaces where I have to sweat multiple potential ways for it to report failures when I just don’t care about the specifics. Sometimes an API doesn’t even have a consistent place that it sticks it’s return code, some don’t even define a reasonable way to know ‘failure’ and require you to explicitly map a huge number of ‘info’ to ascertain if it’s normal or error type state.
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.
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.
misdiagnosing errors originating from transport as application errors, and vice versa.
Shouldn’t the response body disambiguaite clearly whose fault it is? I mean you have to anyway if you advocate for ‘200 for everything’. You still have that same response body whether the HTTP status code is 200 or 500.
We honor the status code while providing an error body and it’s always blatantly obvious whether it’s an infrastructure issue or “true backend” issue when we see an issue. In my team I can’t recall anyone ever getting confused for even a little bit about whether an observed anomaly was web infrastructure or the backend, despite us setting HTTP status codes to error when, you know, we see an error.
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
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” just because it isn’t the way it’s historically been done.
Think the point would be that it’s super easy to also set a ‘non-ok’ status in HTTP. Sure it may be insufficient for sophisticated handling, but at least you can get a vague sense of ‘something went wrong’…
Sure have your more specific API specific error code and your error details in the body, but at least toss a generic ‘500’ into the status code. I often find myself writing client software where I don’t need specific handling I just need to know ‘it failed’, and it’s obnoxious to deal with these interfaces where I have to sweat multiple potential ways for it to report failures when I just don’t care about the specifics. Sometimes an API doesn’t even have a consistent place that it sticks it’s return code, some don’t even define a reasonable way to know ‘failure’ and require you to explicitly map a huge number of ‘info’ to ascertain if it’s normal or error type state.
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.
Shouldn’t the response body disambiguaite clearly whose fault it is? I mean you have to anyway if you advocate for ‘200 for everything’. You still have that same response body whether the HTTP status code is 200 or 500.
We honor the status code while providing an error body and it’s always blatantly obvious whether it’s an infrastructure issue or “true backend” issue when we see an issue. In my team I can’t recall anyone ever getting confused for even a little bit about whether an observed anomaly was web infrastructure or the backend, despite us setting HTTP status codes to error when, you know, we see an error.
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