I know that there are lots of similar posts on this topic, but still none has managed to settle my doubts on this issue. So, I'll try to resume my current scenario. In this case, I've modelled the web services around 3 resources (I'm only interesting in getting resources):
/requests
(with optional query string parameters for filtering);/requests/{id}
/requests/{id}/inquiry
Now, for resource 1 (list of requests), the web service will always return 200 even if there are no requests for the specified filter. For instance, suppose this request:
GET /requests?location=London&priority=1
Would return 200 even if there are no requests from London with that priority
200 OK
[]
I'm doing this because the resource does exist (in this case, the list of resources exists and is identified by url /requests
), but none is compatible with the current query. Returning 200 with an empty list in this case does seem like a good idea, but I'm not really sure if this is compatible with RFC 3986, which says that the complete URL (/requests?location=London&priority=1
) is a resource identifier. That being the case, it would mean that 404 could/should probably be used here. In my opinion, returning 200 with an empty list is the way to go here, but I'd love some feeback.
Getting an individual request (resource 2) seems to be simpler and here I think that 404 is simply a no brainer when someone asks for a non-existing request (ex.: /requests/100
and there is no request with that ID). What do you guys think?
This is a little bit more complicated. Ok, so I've started by modelling inquiry as a resource, which is identified by the URL /requests/{id}/inquiry
. An inquiry is always associated with a specific request (that's why I'm using the previous URL to get an inquiry), but it will only be created after the internal request object (which is also exposed as a resource as shown in scenario 2) reaches a predefined state. My initial implementation of the service followed the same ideas presented for scenario 2: return 404 if there's not an inquiry or 200 with the inquiry data on the response body.
Now, in this case, I've got a couple of doubts about my initial implementation. For instance, if the request exists, but if it still hasn't reached the predefined state where the inquiry gets created, should I return 204 no content
instead? After all, the request is valid and the path to the inquiry is correct. My initial reaction was no, because inquiry was modeled as a resource (and as such, and since it's a single item and not a collection as in scenario 1, then the correct HTTP code to return should be 404). However, there's that dependency on request and if the request exists, then it will be a matter of time until the inquiry is created. What do you guys think?
Btw, I've got one final question: I've been asked how to differentiate between 404 from a bad url vs a 404 from non-existing resource. To me, they're the same (ie, even though if one might not hit the server while the other does hit it and simply there's nothing to return), but I can see value in getting that info on the client (ex.: getting an invalid url due to a mistake might lead to logging which migh help fix things quicker). I know that I can send some info back on the body of the request with extra information, but that won't help much when clients want to process it automatically.
What to return from a rest service when a resource does not exist?
If a server is sending a response to communicate that a resource does not have a current representation, then we'll use a 404
status code, giving general purpose HTTP components a coarse understanding of the response, and indicating certain semantics (ex: can we cache this response for re-use later?)
Both REST and HTTP give you a lot of freedom to decide when your resources have no current representation.
It's perfectly reasonable, for example, to decide that your resources always have a current representation. You might, for example, design your resources so that they have a default representation, which is modified when your server has additional information.
Returning an empty list as the representation of a resource is one example of this idea.
But it doesn't have to be a list; if you consider the paper forms that we are sometimes asked to fill out in the real world, they often start out as a template with a bunch of data fields left blank. We have the freedom to do the same thing with web resources. In the most extreme cases, the "template" would itself be an empty document; and that's fine.
(Whether or not it is ergonomic to do it that way depends on your use cases; HTTP and REST give you the freedom so that you can do that in the cases where it makes sense. Figuring out whether you have a case where it makes sense is on you.)
Returning 200 with an empty list in this case does seem like a good idea, but I'm not really sure if this is compatible with RFC 3986, which says that the complete URL (/requests?location=London&priority=1) is a resource identifier.
It is a good idea, and you can do that. Nothing about returning an empty list conflicts with RFC 3986.
Getting an individual request (resource 2) seems to be simpler and here I think that 404 is simply a no brainer when someone asks for a non-existing request
It's not a "no-brainer"; you should think about whether returning a default representation is a better approach. But situations where returning a 404 is the right choice are common.
should I return 204 no content instead?
Not usually; if you want to communicate that the inquiry resource does have a current representation, and that representation is zero bytes long, then you should return a 200 with a Content-Length of 0.
I've been asked how to differentiate between 404 from a bad url vs a 404 from non-existing resource.... I know that I can send some info back on the body of the request with extra information, but that won't help much when clients want to process it automatically. Any ideas here?
Can't help you much - using the body of the response is usually the right answer. Think of the case on the web: when we want to tell the human being that there has been a problem, we include those fine details in the HTML body.
For APIs, you might want to consider Problem Details.
An interesting thing about problem details: it defines a type member whose value is a URI value that identifies the problem type.
In HTTP, we also have Link Headers, which provides a mechanism for describing the relationship between an anchor URI and a target URI. So if you had a suitable link relation, then you could lift the type from the problem details into the HTTP headers.
The IANA link relations registry includes links to the references for each of the registered relations, so you could look through that list to see if anything suitable has already been registered. Failing that, you could define your own extension relation.
So it might be possible to use a link relation header to provide the affordances clients need to process responses "automatically" (depending, upon other things, what you consider to be "automatic").