Reputation: 2274
In a truly restful application I should follow links to reach my resources, while the only "magical already known URL" should be the application entry point. Direct queries like GET /user/john
should be issued after having at least a link to /user
or as a result from a search url specified by a previous link, like GET /user?username=john
But as following links forces more features, further development time and a smarter client, the actual reality is that most of the restful apis that I have written and used are partially restful: they are a collection of well defined URIs and methods, all previously known to the user by some documentation. In the end, the State Transfer
part of what REST means is not present in most of them.
Well, following that reality where URLs are previously known, the 404
code turns to be an issue: How to differentiate the 2 meanings that 404
can have:
A correct 404
that means "Resource not found, but you can try again in the future". Example: GET /user/mario
while mario is not a registered user
A incorrect usage of the api that means "No resource will ever be found here, you are using this API incorrectly". Example: GET /foobar/123
It is kinda important to differentiate those two scenarios because as a service maintainer, they are basically telling me if its an expect error and I should not be worried (first case) or an unexpected error and I should be worried as the service integration with my clients has issues (second case)
I tried searching for a better status code to represent the second case, and the closest ones I found were the 406 Not Acceptable
(but it is a response directed to an Accept
header that cannot be fulfilled) and the 410 Gone
(that can be confusing as no resource was there, but the good part is that it tells the client to never try that URL again). Nevertheless, none of the two are good enough to be used for solving this
How did you or would you do to solve that?
Side node: python eve is an interesting project that tries to be a restful api with the State Transfer
part. It implements HATEOAS for that
Upvotes: 2
Views: 4747
Reputation: 3171
What about using 403
for the first case (together with the explanation) and 404
for the second? Since the RFC 403 refers to 404 as an alternative response code they might be related...
403 Forbidden: The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.
403: You understand what the client wants but refuse to fulfill it. The client should not try again - it's forbidden until this resource is created - which you can explain as part of the answer.
404: You know that the client wants something you won't provide and can tell him in good faith, that this resource will never exists.
Update:
RFC 2119 explains how the "SHOULD NOT" has to be interpreted:
SHOULD NOT This phrase, or the phrase "NOT RECOMMENDED" mean that there may exist valid reasons in particular circumstances when the particular behavior is acceptable or even useful, but the full implications should be understood and the case carefully weighed before implementing any behavior described with this label.
I think for your use case this is true. The client request shouldn't be repeated *without solving the reason stated in the 403 answer: "accessing this resource is forbidden because no user named mario exists". But if the client is sure that the reason went away, he is free to try again. But this might be only my interpretation of the 403
"should not be repeated" statement.
Upvotes: 2
Reputation: 595762
There is no way to differentiate the two reasons, by design of RFC 2616 Section 10.4.5:
10.4.5 404 Not Found
The server has not found anything matching the Request-URI. No
indication is given of whether the condition is temporary or
permanent. The 410 (Gone) status code SHOULD be used if the server
knows, through some internally configurable mechanism, that an old
resource is permanently unavailable and has no forwarding address.
This status code is commonly used when the server does not wish to
reveal exactly why the request has been refused, or when no other
response is applicable.
Upvotes: 1