70

I'll describe an example:
I start making an API for a baking shop. The API will allow people to search their catalogus for baking products, such as home-made minty chocolate chip cookies using api.examplebakery.com/search?q=......

Someone uses this to look for a product named pineapple-banana flavoured cookies and will obviously not find any results.

Should this be returned as an error? The search did not fail, the API searched and successfully concluded no cookies could be found. The API should not return 404, because the API was indeed found.

15
  • 57
    204 No Content
    – AakashM
    Sep 28, 2017 at 10:52
  • 6
    Possible duplicate of RESTful API represent the absence of a thing
    – gnat
    Sep 28, 2017 at 11:09
  • 3
    @gnat: This is not a duplicate, because the other question is about a specific resource, not a query against multiple resources. Sep 28, 2017 at 16:11
  • 7
    Analogously, suppose you have a function that returns an array of objects. If there aren't any objects that match a particular use case, would you rather the function through an exception or return an empty array?
    – Kevin
    Sep 28, 2017 at 16:36
  • 2
    @AakashM Returning HTTP-204 to a GET request is quite unusual, I know I haven't seen that anywhere. As far as I know, HTTP-204 is usually used as response when modifying a resource on the server, for example POST/PUT/DELETE requests. Sep 28, 2017 at 20:53

6 Answers 6

137

When there are results, the output is a (JSON, based on your comment) list. For queries with no results, the output should be exactly the same. The list simply has 0 items in it.

So if your response is normally this:

{
    "results": [
        {
            "name": "Pancakes",
            ....
        },
        {
            "name": "French Fries",
            ....
        }
    ]
}

Then for a query with 0 results, it should be this:

{
    "results": []
}

If you also include meta data about how many "pages" of results there are, links to those "pages", etc. then I would suggest saying there is 1 "page".

The HTTP status should be the same as when there are results - 200 OK.

204 No Content may also seem to be an option, but it is not because you are in fact returning "content" - the empty list. If you feel an empty list does not count as "content", what if you then amend the response to offer spelling suggestions? The core of the response will still be an empty list, but now there is even more "content".

For more useful information about HTTP status codes, jpmc26 has an answer worth reading.

13
  • 9
    This is the same kind of thinking as the null object pattern. Errors and null aren't the only way to say there's nothing here. Sometimes you want to express your nothing quietly. That way clients don't have to test for nothing. Sep 28, 2017 at 13:12
  • 56
    I'd argue that returning a 204 is inappropriate, as you are returning content. It's just that the content has no results, which is distinct from returning no content at all.
    – TMN
    Sep 28, 2017 at 18:13
  • 9
    @TMN agreed - 204 is not appropriate for "no results." Your query should always return an array, with the results inside the array. If there are no results, the client will handle that naturally. If the client wants to show special text ("No results were found"), then that's fine. 204 should only be returned for an endpoint that does not naturally return a result.
    – JasonB
    Sep 28, 2017 at 19:51
  • 1
    You could use 204 if you were returning null serialised as an empty string I recon
    – Ewan
    Sep 28, 2017 at 21:50
  • 16
    This. The important thing when constructing a RESTful API is the API part, not the restfullness. A good API makes life easy for clients/consumers. An empty array is easier to handle than null values/exceptions/status codes.
    – Guran
    Sep 29, 2017 at 8:14
46

Whenever deciding on an HTTP code, you should always ask this question:

What can/will/should any arbitrary client do with the response?

  1. Should the client always treat the response as a failure? Then you want 4xx or 5xx, depending on whether the problem is the client's input or the server's processes.
  2. Should the client make a request somewhere else instead? Then 3xx is for you.
  3. Did the server do what the client asked (succeeded)? That's 2xx.

Always decide which range your response code should be in first. Doing so quickly eliminates a lot of response codes as options, and (maybe more importantly) it makes following the semantics of the codes much simpler. See the beginning sections of the HTTP code documentation for the explanations of what each category of codes represents.

In this case, the client asked for a list of results given a filter from a valid, existing endpoint and has authorization to access it. The server was able to process the request and determine the appropriate data to return (no items), so the request was successful. It just happens that the filter they gave filtered out all the results. It is not up to the server to determine whether this is what the client wanted or not, since this may be an expected outcome for some clients. If it is somehow a problem for the client code, that is the responsibility of the client to determine, check for, and handle appropriately. So this is clearly 2xx.

Now the question is, "Which 2xx?" This depends on how you intend for the server to respond.

  • Will you send back a representation of an empty list, like some other answers describe? If so, you want 200. 200 means the server experienced no problems and has a representation of the results for the client to consume. This is likely the most convenient way to respond for your consumers, who can just parse the response whether there were results or not and then figure out how to handle an empty list themselves.
  • 204 isn't semantically wrong here, but you would have to respond with no message body whatsoever. This means all client code would have to explicitly check for different HTTP codes (or at least for the lack of a message body) and handle them separately. It's inconvenient and more likely to lead to poorly behaved clients.

The others are not applicable at all:

  • 201 is out of the question. You didn't create any persistent resources and aren't returning a location to a created resource.
  • 202 is out of the question. The request is done; it's not processing in the background.
  • 203 means that the response was modified between the authoritative server and the client. Your RESTful interface is the authoritative server, so this doesn't apply here.
  • 205 doesn't make sense. You don't need the client to clear out or refresh anything.
  • 206 appears to be designed for returning a large resource over multiple responses. It also requires that the client ask for a part of the content in the headers (so pagination via query strings does not qualify). Not applicable here.

So it should either be 200 or 204, and 200 is more likely to lead to simpler, more robust client code (especially if you use a consistent response structure containing an empty list).

4
  • 5
    Would be interested in the downvoter's opinion. I don't think any of this is even controversial.
    – jpmc26
    Sep 29, 2017 at 7:51
  • 2
    I don't think clients have to check for 204 explicitly. All they need is the ability to handle null response object. It's the HTTP framework's job to handle 204 by skipping "parse the body" part. 200 with Content-Lenght 4 and body null is just the same.
    – Agent_L
    Sep 29, 2017 at 14:49
  • 1
    @Agent_L You're right that if the server responds with a structure inconsistent with the normal response (like putting null where there's normally a list), you won't reap the benefits of consistency even with 200. However, what I describe is using a response that's consistent with the normal structure and has an empty list where the list of results would normally go. 204 takes away any opportunity to have such a consistent response. Also, even in HTTP client libraries that have convenience functions for it, you often (typically?) have to make an explicit call to parse JSON.
    – jpmc26
    Sep 29, 2017 at 16:53
  • @Agent_L In particular with lists, callers can often just let their code run normally over an empty list (by looping over it, for example), whereas they'd need an explicit check of some kind to handle another type of representation.
    – jpmc26
    Sep 29, 2017 at 17:06
20

No. the use of 404 to indicate 'your query was processed but there were no matches' is awful because:

  • conditional flow based on exception handling (ie. forcing a non exceptional result to create and handle an exception in the client which can be non performant and awkward)

  • ambiguity between 'real' page not found, you typed the endpoint wrong errors

The thing to remember is that there is always a client to deserialise the message and its what that client returns that's important; not the serialisation.

If the client should return null, then use the serialisation of null. If the client should return an empty array, use [], if the client should throw an error use 500 and pass the error message

13
  • 2
    Why should the server care what the client is doing with the information? (PS: I'm not the one who downvoted your answer). Sep 28, 2017 at 20:58
  • in this context the 'client' is the code running on the client device which exposes the service to the client application. It has to be able expose the services methods and return the results as intended by the service. You need a client-server pair for the communication to function at all
    – Ewan
    Sep 28, 2017 at 21:47
  • 3
    Don't use 5xx for client errors, of course. Prefer 4xx in that case.
    – Kevin
    Sep 28, 2017 at 22:16
  • 1
    Although, shouldn't it be "server", not "client" in most of these instances? It's the server that is processing the request and serving a response, the client just processes the response? In which case a 5xx code would be OK, since it's a server error, not a client error?
    – MrWhite
    Sep 28, 2017 at 22:35
  • 2
    the trouble with all the error codes is that they have meaning within http. 500 is the only code which is suitable for when your service throws an exception
    – Ewan
    Sep 28, 2017 at 23:17
10

Beyond @Ewan's very good answer:

If the query is the kind that returns a set of results, then the empty set is logically just as appropriate as a set of one, or a set of more. Generally speaking for the reasons that @Ewan states, it does more harm than good to alter the empty set into an error, and, it is simply unnecessary.

If the query is the kind that looks up and returns a specific singleton (that is expected to be found, e.g. exact match by id), then not found is a logically appropriate possible response.

1
  • yep I exactly thought that on Ewan's answer.
    – Walfrat
    Sep 29, 2017 at 7:48
5

You're assuming the code has to take a special action when there is no data returned, but that might not be the case. The code might simply be looking for a product count, or appending the results to a list or any number of things. You should only be giving a user an "error" if there is actually an error.

1
  • 3
    "You should only be giving a user an "error" if there is actually an error." - this. An empty results set when performing a "search" is not normally an "error". However, if the database connection failed that meant the search could not actually be performed then an empty results set (and no error) would otherwise be ambiguous. Some kind of error state would be appropriate in this case (perhaps together with an empty results set - depending on how the API is defined).
    – MrWhite
    Sep 28, 2017 at 22:28
1

When I use an API, as a client I have to handle "success" cases different from "error" cases; I have no choice there. Therefore, you should return an error in situations that the client wants to treat differently, and success in situations that the client wants to treat the same.

If I do a query that could in theory return any number of results, zero, one, two hundred and so on, then you should return "success" whenever the API delivers the complete list of all results. And possibly in cases where there are many result, you returned a partial list of results to avoid an excessive size, and there is an agreed way how I would get the other results. That's because as a client, I often want to handle the case of zero results like the case of more results. I might treat it differently, but I don't want to be forced to.

It is different in the case that I lookup a value. I expect exactly one result, the value that I am looking for. And I need that one result to continue what I want to do in a meaningful way. Here it is much more acceptable to return a status 404 for the case that no value is there, because I do need to handle that case differently anyway.

Summary: If the client expects any number of results, from zero to large numbers, then return "success" if all results are delivered, even if the number is zero. If the client expects exactly one result, then return success if the result is found, and an error if the result is not found.

Not the answer you're looking for? Browse other questions tagged or ask your own question.