14

I know this is a fairly common question, but I haven't found an answer that satisfies me.

I've been using django rest framework for a while now, but this is mostly irrelevant other than the example given. Its default behaviour is to return an HTTP 200 with an empty list resource when accessing a route with an empty list of items. E.g.: if we had a route such as /articles/ to access a list of articles but it contained no items we would get a response like the following json:

{"count":0, "next":null, "previous":null, "items": []}

Which is perfectly fine. We found the resource we were looking for at /articles/, it just happens to have no items in it.

If we access the route /articles/?page=1, we get the exact same response.

So far so good. Now we try to access /articles/?page=2, and the response code changes. Now get get a 404 as if the resource could not be found with an error message saying that the page contains no results. Which is the same case as with ?page=1...

I was perfectly ok with this behaviour, but today I started questioning this design. How is the ?page=1 case different than ?page=2 ? And what's more, how could you tell if the request was "valid" when issuing a HEAD request? Valid in the sense of containing any results.

This could be useful in cases like filtering a list checking the availability of a certain field (for example, issuing a HEAD request to /users/?username=ted).

  • A 200 response would clearly mean the request was understood and items were found.
  • A 404 would mean the request was understood, but no items were found at that location/URI (AFAIK the query parameters are also part of the URI)
  • In case the request could not be understood a 400 would be returned for syntactic errors, and a 422 for semantic errors.

Is this a good design? Why do most people seem to disagree with it and what drawbacks are there in it?

marekful
  • 14,986
  • 6
  • 37
  • 59
Rubén Durá Tarí
  • 1,050
  • 1
  • 10
  • 18
  • 4
    IMHO 200 is better because 404 doesn't allow you to differentiate between *no api deployed* and *empty list*. – Davin Tryon May 13 '15 at 14:28
  • Isn't that conceptually the same? There is no resource in that location. A client shouldn't (in theory) worry about endpoints in a proper rest implementation, so that difference shouldn't matter (again, in theory under a proper rest api). – Rubén Durá Tarí May 13 '15 at 14:31
  • 1
    The way I see it: `/articles/` is the list of all articles; even if it's empty, it still exists. And on most sites, even an empty list has a page one, to tell you that there's no results. – Colonel Thirty Two May 13 '15 at 14:38
  • 1
    IMO this design seems fine. A 200 on an empty articles page, meaning there are no articles to be found, lets the the end user know they are in the right place to find a list should it exist. If I found a 404 at `/articles/` I would probably think I was in the wrong place (maybe I should be at `/posts/`) or the link was broken. – kylieCatt May 13 '15 at 14:41
  • 1
    A way to think about IRL terms is going to a store looking for magazines. There is a difference in finding a shelf labeled "Magazines" with nothing on it then not being able to find the shelf at all. – kylieCatt May 13 '15 at 14:44
  • As I said before, a client shouldn't worry about those paths. A previous resource should've led them to it, so the implementer (me) should take care of having those paths properly set. In case we're talking about a cached (and stale) response, a status code of the 3xx range would be more appropriate IMO. – Rubén Durá Tarí May 13 '15 at 14:46
  • 1
    Possible duplicate of [Proper REST response for empty table?](https://stackoverflow.com/questions/13366730/proper-rest-response-for-empty-table) – Franklin Yu Sep 04 '19 at 18:25

4 Answers4

13

I would go for 200 because the resource is articles. While querying for ted in users the same applies, users is the resource and as long it is there, a 200 is okay from my point of view. If you would GET users/ted a 404 would be as good as a 410 (GONE) if a user named ted was there in the past (may better applies to articles than users).

sschrass
  • 7,014
  • 6
  • 43
  • 62
  • What would be the case for /articles/?page=2 when page 2 doesn't exist? Following your same logic, /articles/ exists so a 200 should be returned even though there are no items. Am I right? I would disagree with this design, but as I said on the original post, I understand why some people agree with it. I just happen to follow a different line of thought here. – Rubén Durá Tarí May 13 '15 at 14:50
  • 3
    `/articles/?page=2` would result in an 200 reponse containing an empty list, because there are articles, but none on the second page. – sschrass May 13 '15 at 15:00
  • 3
    I use to think of it like a db query, where the resultset is empty, but the query is syntacticly okay. – sschrass May 13 '15 at 16:16
  • I guess that is where of way of thinking differs then. :P – Rubén Durá Tarí May 13 '15 at 16:17
  • If a request had a wrong syntax the appropriate response code would be 400 anyway (or a 422 if it was syntactically ok, but semantically made no sense) – Rubén Durá Tarí May 13 '15 at 16:18
  • 2
    what about http 204, a compromise of 200 and 404? I don't know usecases for 204, but it sounds okay. "everything was perfectly fine, but there is no content" – sschrass May 13 '15 at 20:00
  • I believe 204 semantics are not what I need in here. 204 just means the server does not NEED to return a response. Maybe there is content, but the server decides not to return it for whatever reason. In the design I propose I would need to explicitly say that there is no content available on that URL. Also, if I recall correctly, 204 is not a valid response code for GET requests according to the RFC, but I might be wrong on this one. – Rubén Durá Tarí May 13 '15 at 23:44
  • Could an empty JSON like in the question justify the "no need to return a response"? A client could not make any use of it. – sschrass May 15 '15 at 06:51
  • I think the response to this lies in RFC 7231: The 204 response allows a server to indicate that the action has been successfully applied to the target resource, while implying that the user agent does not need to traverse away from its current "document view" (if any). [...] For example, a 204 status code is commonly used with document editing interfaces corresponding to a "save" action, such that the document being saved remains available to the user for editing. In my case the user is navigating to a different resource, it doesn't seem to fit. – Rubén Durá Tarí May 15 '15 at 09:21
  • It also seems a bit weird how these RFCs explicitly mention using 204s for POST, PUT and DELETE responses, but not for GETs. A 204 might create some confusion on some clients as the semantics seem to be different than a 404 or any other 2xx. – Rubén Durá Tarí May 15 '15 at 09:22
  • A query is an action on a target resource and in this case the user agent does not need to traverse away. I would need to look it up myself, but a page=2 is not neccessarily a new resource you navigate a user to. It is still the articles resource but only a subset from a query. If you would introduce a paging param you could change results (size=10&page=2 vs. size=20&page=2) while the resource users is still the same. – sschrass May 15 '15 at 10:05
  • How does that relate to getting a first empty page? Say if we navigate to /articles/ from a different resource but there are no articles. In this case we still need a resource representation as the user navigated from somewhere else, and a 204 in that case might not be appropriate. I still believe a 204 is not the most appropriate response code as we're not acknowledging an action has been taken, but rather changing the resource. I do think that changing the query implies changing the resource, thus we need a response for the user to keep navigating. – Rubén Durá Tarí May 15 '15 at 10:13
  • "A resource can map to the empty set, which allows references to be made to a concept before any realization of that concept exists" --R. Fielding 5.2.1.1 I would say this takes out 404 as response and it must be a 2xx. Telling the client that there is no content (204), still tells him that there could be in the future. 200 tells him to look into the response and handle null and should assume that there may is data in the future. – sschrass May 15 '15 at 11:23
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/77902/discussion-between-ruben-dura-tari-and-satellitesd). – Rubén Durá Tarí May 15 '15 at 13:44
  • I'll copy my comments on the chat just in case you missed it @SatelliteSD So, unless I misunderstood you, whenever the path exists a 2xx response will always be returned. If the full URI (including query parameters) results in an empty resource a 204 should be returned. A 404 will be reserved for non existing paths. That makes it rather consistent in most cases I think. I you write this answer in a new response I'll be happy to accept it. :) – Rubén Durá Tarí May 21 '15 at 10:06
4
  1. Because we are ok with an empty page1, not ok with an empty page2.

This is driven by the UI consideration (page1 must exist!), nevertheless, it decides the response code.

ZhongYu
  • 19,446
  • 5
  • 33
  • 61
3

This really boils down to the "null vs empty collection" argument. The cases for null are also cases for HTTP 404, and the cases for an empty collection are also cases for HTTP 200.

if we had a route such as /articles/ to access a list of articles but it contained no items

Assuming this is a global list of articles, i.e:

http://mywebsite/articles

then this response can never be null, and therefore should never be a 404. The global list of articles always exists, and therefore the collection is always not-null, regardless of whether it contains elements or not.

A simple example here is thinking of a SQL query. If a table exists, even if it's empty, a query will return a result (be it empty or not), so use 200. If the table itself does not exist, you get a query error, so 404.

But if the articles are contained within another resource, e.g. their author:

http://mywebsite/authors/johndoe/articles

Now we get to the part where null (and thus 404) is meaningfully possible.

  • If johndoe exists and has articles, you return a non-empty list
  • If johndoe exists and does not have articles, you return an empty list and HTTP status 200
  • If johndoe does not exist, then you return null and HTTP status 404

This communicates the correct response to the user. 200 reveals that the data was correctly fetched, whereas 404 reveals that the requested resource simply does not exist.


Note that this is slightly different when referring to a specific article instead of a list. When returning a specific resource (or not), instead of a list, 404 is the only correct HTTP status for a 'no item' response.

http://mywebsite/article/1

Here, you either return the article or null.

http://mywebsite/authors/johndoe/articles/1

Here, you return 404 when either author johndoe or article 1 does not exist.

Flater
  • 12,908
  • 4
  • 39
  • 62
0

200 simply means the request has succeeded. The information returned with the response is dependent on the method used in the request, for example: GET an entity corresponding to the requested resource is sent in the response;

HEAD the entity-header fields corresponding to the requested resource are sent in the response without any message-body;

POST an entity describing or containing the result of the action;

TRACE an entity containing the request message as received by the end server. 404 - The server has not found anything matching the Request-URI - In this case I think it means we did not find the page that articles would have been listed on. So 200 it is. - but perhaps understand what is being returned and format a message that 0 article have been returned.