My question is, should I return a HTTP response code of 400 Bad Request, 404 Not Found or 410 Gone when a parent resource, or higher, does not exist / has been deleted?
Looking for some guidance around how to handle a missing links in a RESTful resource tree, as I've read quite a bit but not a whole lot of personal experience.
Say we have the resources structure below:
/users/{userId}/accounts/{accoundId}/logs/{logId}
One user can have many accounts, which in turn can have many orders, which in turn can have many logs. Logs only exist against a single account, and accounts only exist against a single user. Logs cannot exist without an account, and accounts cannot exist without a user.
My problem comes when I try to resolve the below:
/users/123/accounts/321/logs - POST
/users/123/accounts/321/logs/987 - GET
/users/123/accounts/321/logs/987 - PUT
/users/123/accounts/321/logs/987 - DELETE
/users/123/accounts/321/logs/987 - PATCH
/users/123/accounts/321/logs/987 - HEAD
But this resource does not, or no longer, exists:
/users/123/accounts/321
or this resource does not, or no longer, exists:
/users/123
I could argue it's a 400 Bad Request, which as per RFC7231:
6.5.1. 400 Bad Request
The 400 (Bad Request) status code indicates that the server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).
Would be by definition true, except in the scenario that a cache hadn't expired, meaning the application had yet to re-traverse the hierarchy, and another application had deleted the parent resource. By providing a relevant oplock, the client will have proven that as per its last knowledge, it was making a semantically correct request.
I instinctively would have lent towards 404 Not Found or 410 Gone even if this wasn't a cache thing, as the cause of the failure was literally a missing/unavailable resource. However as per the spec RFC7231:
6.5.4. 404 Not Found
The 404 (Not Found) status code indicates that the origin server did not find a current representation for the target resource or is not willing to disclose that one exists. A 404 status code does not indicate whether this lack of representation is temporary or
permanent; the 410 (Gone) status code is preferred over 404 if the
origin server knows, presumably through some configurable means, that the condition is likely to be permanent.
or
6.5.9. 410 Gone
The 410 (Gone) status code indicates that access to the target
resource is no longer available at the origin server and that this
condition is likely to be permanent.
These would appear to give the lie to that instinct.
Does anyone have any experience in dealing with this, or similar, scenarios and good approaches? I feel I should go with what feels right and what I'd expect to see if consuming this service, rather than the letter of the text.
404: “The requested resource was not found.” This is the most common error message of them all. This code means that the requested resource does not exist, and the server does not know if it ever existed.
If the server does not know, or has no facility to determine, whether or not the condition is permanent, the status code 404 (Not Found) SHOULD be used instead. This response is cacheable unless indicated otherwise.
We tend to get -1 status codes when there are network issues or connection problems, so we display the user a network problems page in those cases.
The 200 status code is by far the most common returned. It means, simply, that the request was received and understood and is being processed. A 201 status code indicates that a request was successful and as a result, a resource has been created (for example a new page).
A thing to keep in mind: the HTTP response, including the metadata, which includes the status code, are specific to the requested resource, not some implicit hierarchy of things.
Which is to say
GET /users/{userId}/accounts/{accoundId}/logs/{logId}
requests: a current selected representation for the target resource. See RFC 7231; in particular, the request doesn't ask about representations of any of these:
/users/{userId}/accounts/{accoundId}/logs/
/users/{userId}/accounts/{accoundId}/
/users/{userId}
...
It's much simpler than that - can I have what I asked for? And the origin server provides a response, which may be a current representation, or it may be a message explaining that no such representation is available.
The fact that no representation of /users/{userId}/accounts/{accoundId}/logs/{logId}
is available because /users/{userId}/accounts/{accoundId}
does not exist is an implementation detail.
404 is normally what you would want to use as a status code to announce that no current representation of the target resource is available. Any explanation for why this is the case would normally go into the message body. For instance, you might describe it using problem details.
The server is not obligated to send an expired representation of a resource just because it happens to have one lying around (again, the cache is an implementation detail).
410 is almost the same thing; it's effectively an advisory that the client can mark its bookmarks as deprecated.
400 is a perfectly reasonable way to punt if you can't find a status code that better fits the semantics of the message in the payload. But I wouldn't use if for this case where 404
does actually fit your needs.
NO: Rule out the 400 Bad Request as all the requests, which you have mentioned, are valid.
NO: To add some spice: I've seen a 409 Conflict being returned in similar cases. It appears inappropriate in your situation though as you clearly indicated that a resource is missing.
YES: A 404 Not Found is the most appropriate response if your resource does not exist. It doesn't matter if it ever existed or not. The 404 indicates a "sorry, resource unavailable". I would add an error message to be precise about which resource is missing so that your API consumers can handle the situation better.
MAYBE: A 410 Gone is a specific case of a 404. It should be raised if the resource is unavailable and it existed before and it will (practically) never exist again. So no matter how often and when you try to get the resource, you'll never get it again, but in the past, you may have been able to get it. Same thing here: if you decided on a 410 consider adding a precise error message.
On a personal note:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With