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.

Berry M.
  • 829
  • 1
  • 6
  • 6
  • 57
    [204 No Content](https://httpstatusdogs.com/204-no-content) – AakashM Sep 28 '17 at 10:52
  • How about in a JSON response, then? Should it have status `true` or `false`? – Berry M. Sep 28 '17 at 10:54
  • What does the `status` mean or represent? – AakashM Sep 28 '17 at 10:57
  • You can either us the 204 HTTP status of the response as stated AkashM or use a way on your own with some JSON or whatever. Personally at the moment, I just return an empty list. – Walfrat Sep 28 '17 at 11:02
  • 6
    Possible duplicate of [RESTful API represent the absence of a thing](https://softwareengineering.stackexchange.com/questions/358020/restful-api-represent-the-absence-of-a-thing) – gnat Sep 28 '17 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. – Greg Burghardt Sep 28 '17 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 '17 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. – Radu Murzea Sep 28 '17 at 20:53
  • I'd say: it depends. – JensG Sep 29 '17 at 10:16
  • 2
    Did you ever stop to consider the possibility of returning [HTTP status code 418](https://tools.ietf.org/html/rfc2324#section-2.3.2)? While not *directly* applicable, it could probably be used by metaphor. – user Sep 29 '17 at 12:52
  • 1
    @MichaelKjörling That seems improper use of 418 to me. It should only be used when the server in question is actually a teapot. – JAB Sep 29 '17 at 14:20
  • 1
    I would eat those cookies – USER_8675309 Sep 29 '17 at 18:46
  • 2
    You don't have "no result". You have a result, which is an empty list of products. – gnasher729 Sep 30 '17 at 12:25
  • 2
    [Here's one recipe](http://www.thelazyveganbaker.com/recipe/caramelized-pineapple-banana-drop-cookies/). – user117529 Sep 30 '17 at 19:14
  • Everything went fine, there just wasn't a result so you shouldn't return an error. In another use case where getting 0 results is unexpected, return an error. – Pieter B Oct 01 '17 at 10:31

6 Answers6

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.

wortman
  • 3
  • 2
Jory Geerts
  • 1,511
  • 1
  • 10
  • 11
  • 9
    This is the same kind of thinking as the [null object pattern](https://en.wikipedia.org/wiki/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. – candied_orange Sep 28 '17 at 13:12
  • @CandiedOrange I'm confused. Are you saying that I'm suggesting a variant of the null pattern (which I would disagree with), or are you saying that I'm making it so "clients don't have to test for nothing"? – Jory Geerts Sep 28 '17 at 13:29
  • I'm saying the two are one and the same. The simplest form of the null object pattern I've ever seen is this string: "" – candied_orange Sep 28 '17 at 16:44
  • 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 '17 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 '17 at 19:51
  • 1
    You could use 204 if you were returning null serialised as an empty string I recon – Ewan Sep 28 '17 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 '17 at 08:14
  • Thank you for your insights! I will be taking this and other answers along in my application! – Berry M. Sep 29 '17 at 12:43
  • 1
    204 means that HTTP body is absent. An empty Json object constitutes at least 2 bytes, so 204 is not appropriate. It all depends if you have absolutely nothing to tell your clients in that case and you want your clients to handle root object as null gracefully. – Agent_L Sep 29 '17 at 14:45
  • 1
    I've seen at least one HTTP client library that, when confronted with a 204 status, actually discards any body returned by the server; thus: you won't necessarily be _able_ to include meaningful content, even if you wanted to. – Roger Lipscombe Sep 29 '17 at 18:16
  • I've updated the last part of the answer about the status code. Thanks guys! :) – Jory Geerts Oct 02 '17 at 07:37
  • how about 202? The request has been accepted for processing, but the processing has not been completed. I mean like maybe client search for user id 9 and it should returned user profile and maybe additional data like transactional data, since client id not found then process not complete – Yohanim Oct 18 '21 at 07:39
  • @Yohanim The processing of *this request* ("give me all users with ID=9") is has been completed; the result of that processing is "there is no user with ID=9". Note: "ID=9" sounds like you're doing `GET /users/9` - in that case, if there is no user, `404 Not Found` would be the correct response code. Also see [jpmc26 their answer](https://softwareengineering.stackexchange.com/questions/358243/should-no-results-be-an-error-in-a-restful-response#answer-358293). – Jory Geerts Oct 18 '21 at 12:26
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).

jpmc26
  • 5,389
  • 4
  • 25
  • 37
  • 5
    Would be interested in the downvoter's opinion. I don't think any of this is even controversial. – jpmc26 Sep 29 '17 at 07: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 '17 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 '17 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 '17 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

Ewan
  • 70,664
  • 5
  • 76
  • 161
  • 2
    Why should the server care what the client is doing with the information? (PS: I'm not the one who downvoted your answer). – Radu Murzea Sep 28 '17 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 '17 at 21:47
  • 3
    Don't use 5xx for *client* errors, of course. Prefer 4xx in that case. – Kevin Sep 28 '17 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 '17 at 22:35
  • the client just wraps the service, so there really isnt a distinction unless we are talking deserialisation errors and the like – Ewan Sep 28 '17 at 23:12
  • 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 '17 at 23:17
  • @MrWhite I believe that OP's reasoning is that situation could be interpreted as 4XX because it was client's "fault" to issue a query that produces no results. It all boils down to decision: is empty set a valid set? – Agent_L Sep 29 '17 at 14:53
  • @Ewan - "500 is the only code which is suitable for when your service throws an exception": I disagree. It depends on the exception and the circumstances in which it is thrown. An input validation exception could plausibly trigger either 400 or 422. 409 is an appropriate response for a variety of exceptional circumstances caused by concurrency issues. 503 is appropriate for resource allocation failures. – Jules Oct 01 '17 at 06:54
  • those errors are appropriate for the web _server_ which hosts your service to throw. not your service – Ewan Oct 01 '17 at 08:22
  • I can't upvote your answer because of this: "conditional flow based on exception handling." This is a platitude, albeit a common one. The reality is that exceptions *are* flow control; that is the reason for their existence. Saying that we shouldn't use them for flow control is not a helpful statement when trying to determine how to appropriately use them. – jpmc26 Oct 01 '17 at 09:19
  • that is true. I could edit to make it more nuanced... its a bit of a separate discussion though – Ewan Oct 01 '17 at 09:23
  • there, edited..... – Ewan Oct 01 '17 at 09:27
  • out all of these answers the second bullet point here finally made the most sense to me. 404 is for like an endpoint that doesn't exist. – Connor Apr 28 '20 at 10:14
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.

Erik Eidt
  • 33,282
  • 5
  • 57
  • 91
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.

John Smith
  • 135
  • 4
  • 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 '17 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.

gnasher729
  • 42,090
  • 4
  • 59
  • 119