That’s not what HTTP errors are about, HTTP is a high level application protocol and its errors are supposed to be around access to resources, the underlying QUIC or TCP will handle most lower level networking nuances.
Also, 5xx errors are not about incorrect inputs, that’s 4xx.
Standardize a response body across your APIs that specifies the cause of the non-2xx response. Have an enum per API/service for causes. Include them in the API doc.
If anyone still doesn’t get it, quietly dispose of them at your friend’s pig farm.
And it’s not even always a simple case of “that resource doesn’t exist”. A 404 could also mean that the resource does exist but the current authenticated user doesn’t have the correct permissions to access it, so it’s more like “as far as you know that resource doesn’t exist”. Some people might argue that 403 should be used for that, but then you’re telling potential bad actors that maybe shouldn’t even have access to your documentation that they have indeed found a valid endpoint.
Avoiding 403 seems like a security through obscurity approach to me.
I suppose there might be some special admin only endpoints you’d want to 404 on if the user is not an admin. But for most cases it’s really hell integrating an API that 404s on everything… is my token invalid, did I set a parameter wrong, or did I get the path wrong? I guess I gotta spend all day doing trial and error to figure it out. Fun!
Also makes integration tests on your security unreliable. Someone renames an endpoint and suddenly your integration tests aren’t actually testing security anymore. Checking for 403 and getting a 404 because someone renamed something will indicate the test needs to be updated to use the new path. Checking for 404 (because the user isn’t supposed to have access) and getting 404 (because the path was changed) means your test is useless but you won’t know it was rendered useless.
It depends on the context. If it’s an URL that is easy to guess and reflects user-created content, your system is leaking information about their users if it returns 403. The example that comes to mind is GitHub returning 404s for both nonexisting and private repos when the authenticated user doesn’t have access to it.
Some osint tools use this : they test an email on thousands of services, and use the error result (403/404) to know if the person has an account there.
404 is for “I can not confirm this resource exists”
For example, a private github repo must return 404 for unauthorized users, API requests must act as if that repository doesn’t exist (including returning 404 status codes).
403 is for “I can confirm this resource exists, you cannot access it”
I usually treat a path as a series of dereference operations, each with a potential security precondition. You could protect /secure/… with credential checks, and report 403 at that point, before even looking at the rest of the resource path. It exposes the prefix but not the multiple endpoints that might exist below that point.
You can send 4xx errors yourself too. If the client needs to change something about the request, that’s a 4xx, like 400 Bad Request. If the server has an error and it’s not the client’s fault, that’s a 5xx like 502 Bad Gateway.
The wikipedia listing of all HTTP codes is quite helpful. People also forget you can send a custom response body with a 4xx or 5xx error. So you can still make a custom JSON error message.
A 2xx means success to its requester. If you have an error in step 6 out of 13 that breaks the resource action, you shouldn’t be returning a success.
You might argue what to return and what kind of information to include in the response (like tracking numbers), but it shouldn’t be a 2xx and I don’t see how a misleading 200 would be more helpful than a 400 bad request.
and to just send “Bad request” when it’s a good request - does not make sense
That’s when you use a 5xx status, then. The client doesn’t care how many other services you reach out to in order to fulfill their request. A 5xx code also covers failures in other parts of the system.
Except of course that http has a myriad of response codes that are more useful than a 200 with an error body. This was a serious mistake of GraphQL imo
What’s wrong with graphql over a web socket? Graphql doesn’t necessitate http or any other transport method, it can be done via pigeons. Graphql has zero control over how http works when you use graphql over http, it doesn’t force implementors to use http at all
I used SOAP in my first web dev job over a decade ago when I was making flight search software and connecting to horrific APIs owned by the airline industry to get flight details and purchase tickets. Why are these two things even remotely the same? It’s closer to SQL than SOAP, and I’d choose graphql over any soap api. I still wouldn’t do it over http if I could avoid it though.
Then complain to Apollo or whoever created the server, not the graphql spec. I’ve used graphql over a web socket on production apps for almost a decade now. I don’t use http for graphql if I can avoid it and I always have been able to.
deleted by creator
That’s not what HTTP errors are about, HTTP is a high level application protocol and its errors are supposed to be around access to resources, the underlying QUIC or TCP will handle most lower level networking nuances.
Also, 5xx errors are not about incorrect inputs, that’s 4xx.
I’ve had fellow developers fight me on this point, in much the same way as your parent post.
“If you return a 404 for a record not found, how will I know I have the right endpoint?”
You’ll know you have the right endpoint because I advertised it—in Open API, in docs, etc.
“But, if
/users/123
returns a 404, does that mean that the endpoint can’t be found or the record can’t be found?”Doesn’t matter. That resource doesn’t exist. So, act appropriately.
Standardize a response body across your APIs that specifies the cause of the non-2xx response. Have an enum per API/service for causes. Include them in the API doc.
If anyone still doesn’t get it, quietly dispose of them at your friend’s pig farm.
It’s not like you can’t return a body with the 404 that specifies that the user itself is not found versus the ending being wrong.
And it’s not even always a simple case of “that resource doesn’t exist”. A 404 could also mean that the resource does exist but the current authenticated user doesn’t have the correct permissions to access it, so it’s more like “as far as you know that resource doesn’t exist”. Some people might argue that 403 should be used for that, but then you’re telling potential bad actors that maybe shouldn’t even have access to your documentation that they have indeed found a valid endpoint.
Avoiding 403 seems like a security through obscurity approach to me.
I suppose there might be some special admin only endpoints you’d want to 404 on if the user is not an admin. But for most cases it’s really hell integrating an API that 404s on everything… is my token invalid, did I set a parameter wrong, or did I get the path wrong? I guess I gotta spend all day doing trial and error to figure it out. Fun!
Also makes integration tests on your security unreliable. Someone renames an endpoint and suddenly your integration tests aren’t actually testing security anymore. Checking for 403 and getting a 404 because someone renamed something will indicate the test needs to be updated to use the new path. Checking for 404 (because the user isn’t supposed to have access) and getting 404 (because the path was changed) means your test is useless but you won’t know it was rendered useless.
It depends on the context. If it’s an URL that is easy to guess and reflects user-created content, your system is leaking information about their users if it returns 403. The example that comes to mind is GitHub returning 404s for both nonexisting and private repos when the authenticated user doesn’t have access to it.
Some osint tools use this : they test an email on thousands of services, and use the error result (403/404) to know if the person has an account there.
No.
404 is for “I can not confirm this resource exists”
For example, a private github repo must return 404 for unauthorized users, API requests must act as if that repository doesn’t exist (including returning 404 status codes).
403 is for “I can confirm this resource exists, you cannot access it”
I usually treat a path as a series of dereference operations, each with a potential security precondition. You could protect /secure/… with credential checks, and report 403 at that point, before even looking at the rest of the resource path. It exposes the prefix but not the multiple endpoints that might exist below that point.
deleted by creator
You can send 4xx errors yourself too. If the client needs to change something about the request, that’s a 4xx, like 400 Bad Request. If the server has an error and it’s not the client’s fault, that’s a 5xx like 502 Bad Gateway.
The wikipedia listing of all HTTP codes is quite helpful. People also forget you can send a custom response body with a 4xx or 5xx error. So you can still make a custom JSON error message.
deleted by creator
A 2xx means success to its requester. If you have an error in step 6 out of 13 that breaks the resource action, you shouldn’t be returning a success.
You might argue what to return and what kind of information to include in the response (like tracking numbers), but it shouldn’t be a 2xx and I don’t see how a misleading 200 would be more helpful than a 400 bad request.
deleted by creator
That’s when you use a 5xx status, then. The client doesn’t care how many other services you reach out to in order to fulfill their request. A 5xx code also covers failures in other parts of the system.
deleted by creator
https://www.loggly.com/blog/http-status-code-diagram/
That’s still a 4xx situation.
Except of course that http has a myriad of response codes that are more useful than a 200 with an error body. This was a serious mistake of GraphQL imo
What’s wrong with graphql over a web socket? Graphql doesn’t necessitate http or any other transport method, it can be done via pigeons. Graphql has zero control over how http works when you use graphql over http, it doesn’t force implementors to use http at all
Aww a whole new generation of devs get to make the same mistakes SOAP made. Makes me feel all fuzzy inside.
I used SOAP in my first web dev job over a decade ago when I was making flight search software and connecting to horrific APIs owned by the airline industry to get flight details and purchase tickets. Why are these two things even remotely the same? It’s closer to SQL than SOAP, and I’d choose graphql over any soap api. I still wouldn’t do it over http if I could avoid it though.
Meanwhile, in the real world…
Then complain to Apollo or whoever created the server, not the graphql spec. I’ve used graphql over a web socket on production apps for almost a decade now. I don’t use http for graphql if I can avoid it and I always have been able to.