For a search with no results, should the HTTP response be 404, 204 or 200 with an empty body?

Asked

Viewed 4,843 times

23

When we search for a resource on the server with some type of filter, for example, a user search, a list with the data is returned (in JSON, XML or even already formatted in HTML)

But some searches may result in no data, so a request to /users/name/guilherme, since there is this route, but there is no user with the name Guilherme, the most semantically correct is to return the code 404 or an empty array ([])?

The same applies when searching for something specific, such as searching for the (singular) N-id user (/users/7)? In case instead of returning a [] would return null

Question for reward:

The status 204 No Content, according to rfc 7231:

Status code 204 (No content) indicates that the server has successfully solved the request and that there is no content to send in the body of the reply

This can be interpreted as a query that does not return any record. But also as a request that returns a 204 should always return that same status regardless of whether there have been changes in the data, if there is a change in the return, it should be understood as a change in the API (unless it returns some error status)

So what scenario would be correct use? Both?

  • Return the status 200 with an empty array. The status 404 should be used for when a resource is not found (for example, the URL does not exist). In your example, the URL exists, what does not exist are the data.

  • According to the W3, in the protocol of definitions of status code: 404 = O servidor encontrou nada que corresponda ao URI de solicitação.

  • 1

    I always use the 404 Notfound, and many projects on github also use the 404, I like to follow this pattern because it is self-explanatory and widely used. The following is a nice article on the subject: https://www.infoq.com/articles/webber-rest-workflow

  • This is totally relative and based on the interpretation and definition of who builds the API, for example, I believe that 404 should not be used, since it serves to tell if you managed to make the call to the service, and that it is not out of the air. I would use 204 (No-Content) since the server is in the air, performed the search, and found no content.

  • Using the example of the links of @Samuel, 404 for me would be "hey barista see me a drink" and the barista is not in the bar at the moment, and 204 would be "hey barista see me drink X" and he replies "unfortunately I do not have the X"

  • @I disagree with the use of 204. This code means the server did everything right, but don’t need return a given. A good example of this is in requests of the type DELETE, that you don’t need to return the deleted data.

  • @considering the different responses in the comments I would say that is a pertinent question, and I do not think "relative and based on the interpretation and definition of who builds the API", because, although the person can create an API that deletes data with the verb GET, is semantically incorrect, just as there is a status a better way to respond to the request in these scenarios

  • @William, I take into consideration Richardson’s Model of Maturity, The GET representation can be correct for DELETE? Yes, or not! If you model your API considering the last level of maturity is wrong, if it models at another level the GET representation meets, it is different to make a DELETE request to users/1 and do a GET to deleteUser/1. Are both correct? Yes! Both answer? Yes! As said is relative

  • The return of a DELETE can also be 200 because the entity has been deleted, may be 204 for no return, fits the interpretation of who created the API documenting which code is using

Show 4 more comments

3 answers

40


First, I must say that one of the Urls seems to be poorly built.

The text means that the URL /users/name/guilherme return all users it has name equal to guilherme. If it is a search, it is not a server resource, then it cannot be mapped to a "Uniform Resource Locator". Searches are made by query strings, then the URL should be something like:

/users/?name=guilherme

In this case, the path that will be accessed on the server¹, defined by path of the URL, will be /users, so the resource will be properly located, the search will be carried out and, in this case, no results will be found. This situation configures a request successfully handled by the server, so a "200 OK" response; as no results were found, probably the body of the answer will be an empty list or analogous structure:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "total": 0,
    "users": [],
    "query": {
        "name": "guilherme"
    }
}

Note that returning an empty list does not mean responding with the empty body. This will hardly be recommended. Explicit is always better than implicit. For example, in the above answer was not only returned "users": [] indicating the absence of results as it was returned "total": 0 and the search performed. Who will treat the answer will have no doubt that the search was made successfully and did not get results. Having no doubts is a sign of absence of ambiguity and this is always interesting.

Already to the URL /users/7 the situation changes. You are not searching, but accessing a server-specific resource. In this case, there is no user with identifier equal to 7, the return must be "404 Not Found".

As commented on in Skipping route due to badly formatted parameter is a syntax error? 404 will indicate that at the time of the request the resource does not exist, but in the future it may exist. This is important for the client who is making the request as they will know that they will be able to make the same request in the future and get a different response.

But note, this is not a rule, just something that approaches the idiomatic of HTTP, as it seeks to eliminate redundancy to the maximum. Depending on the requirements redundancy can be beneficial when it is of interest to practice the security for obscurantism². In some cases generating redundancy in HTTP responses is purposeful to hide the API implementation rules, but this is a difficult context to work, as increasing redundancy you intrinsically increases the degree of difficulty of integrations.

It is common, however, to see Apis with the return to /users/?name=guilherme and the answer is 404 in the same way:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
    "total": 0,
    "users": [],
    "query": {
        "name": "guilherme"
    }
}

And it is also common to see the response with the body indicating the details of the answer, which would decrease the redundancy in this example. If you reduce redundancy by the body, the answer code becomes superfluous, so it will depend directly on the implementation rules of your project, just try to be coherent. When defining the answer in one of these resources, use it for all similar resources. A 404 response to /users/?name=guilherme and an answer 200 to /posts/?category=sports would leave your API incoherent and further undermine any integration.

204 No Content

The 204 answer should not be used to indicate that the search had no results. Semantically speaking - and this is what matters when we analyze in depth which answer to use - when we do a search we expect as a result a list; when the search has no results, we will be expected to receive an empty list. The server received the request, understood it and was able to interpret and execute it. Returning the answer 204 in this case will imply that the customer assumes by inference that there have been no results, but will never give the security of it.

It would be the same as you coming to a peddler, asking if he has the balls to sell and he doesn’t answer you. You can understand that by not having answered you he does not have the tomatoes, but it may also be that he did not understand that it was a question and therefore judged that there was no need for an answer. Generating customer questions is not semantic. Different customers can understand differently and confusion will be armed. You can even document your API very well and make it explicit that there will be 204 returns when no result is found, but in this case you end up generating a very large dependency with your own documentation without any kind of benefit.

When the 204 No Content answer should be used?

When the response to the request does not require a body. The most common situation is in information updates. Imagine the situation: the user accessed your profile on the site, went into editing profile and thus is seeing all the current information in the form. He then decides to change some fields and save. At this time the user already has all the updated information on the screen, why would you transmit this same information from the server to the client when you already have it in the client? That would add an unnecessary burden to communication. For the client itself, this may not make much of a difference; the extra time spent transmitting the body would possibly be a few milliseconds (or seconds in worse cases)³, but nothing that would affect the usability of the API. However, for a server that needs to respond to thousands of requests per hour, this information unless it doesn’t need to submit can make a lot of difference.

Imagine that you need to ask the intern to change the position of the coffee maker in the office. Today she stays in the kitchen, but you want her installed on your table. You can go to the intern and ask "Greetings earthling, please change the position of the coffee maker. Bring her from the kitchen to my table". The intern, as efficient as ever, promptly makes the change and in order to inform you that the task has been performed he comes to you and answers one of the options below:

  1. Ready!
  2. Okay, I moved the coffee maker. Now it’s installed on your desk.

Do you agree that both answers are complete and leave no doubt as to what has been done? Even if the answer is only "Done!" , you already knew that the coffee maker was in the kitchen and that it would be installed on your table, so only one confirmation would be enough. Similarly, the second answer also gives you confirmation that the task has been accomplished, with the difference that it also states what you already knew.

In the HTTP response it is the same thing. If you already have current knowledge and you modify it, you have all the necessary tools to infer what the new state of the resource will be, so only a confirmation of success will suffice.

In fact, the answer 204 No Content usually has the Etag header, which is a unique value responsible for identifying the state of the resource. Thus, along with the information of the resource you will have the current Etag of the same, which you must send along with the update request through the If-Match header. If the resource on the server is in exactly the same state as the client, the update is authorized and the new Etag is returned in the reply. If the resource is in a different state than the client, the updating of the information should be refused by informing the client that the version of the resource he owns is outdated. This avoids the problem of "Lost update".

Let’s assume the situation: I have the information of a user (name and email) and I want to update them. I access the resource:

>> GET /user/1 HTTP/1.1
>> Host: localhost
>> ...

Getting the answer:

<< HTTP/1.1 200 OK
<< Content-Type: application/json
<< ETag: 1000001
<< ...
<<
<< {"name": "Anderson Carlos Woss", "email": "anderson@localhost"}

I change the email and have it saved, thus making the update request:

>> PUT /user/1 HTTP/1.1
>> Host: localhost
>> Content-Type: application/json
>> If-Match: 1000001
>> ...
>>
>> {"email": "anderson@woss"}

In this case, I have the original name and email and know what has been changed, so I know that the new state will be {"nome": "Anderson Carlos Woss", "email": "anderson@woss"}, the response to the request need not tell me this, it would be redundant. So a possible response using HTTP 204 would be:

<< HTTP/1.1 204 No Content
<< ETag: 1000002
<< ...

Note that the response will inform the new Etag value indicating the new resource identifier. If another update request is made stating the old value, the update does not occur and the 412 Precondition Failed response will be returned:

>> PUT /user/1 HTTP/1.1
>> Host: localhost
>> Content-Type: application/json
>> If-Match: 1000001
>> ...
>>
>> {"email": "john@due"}

The answer would be:

<< HTTP/1.1 412 Precondition Failed
<< Content-Type: application/json
<< ETag: 1000002
<< ...
<< 
<< {"error": "As informações estão desatualizadas. Atualize-as antes de fazer uma edição"}

This would prevent the first change from being overwritten by the second ("Lost update problem").


(1): Remembering that the URL is an opaque value and does not necessarily reflect the server implementation, so say the path accessed on the server from the path URL is not always valid.

(2): Security by obscurantism: What is called the technique of hiding components to ensure information?

(3): Disregarding special cases where the body of the answer could be gigantic.

  • 1

    A real class, very good.

5

I would use 404 as well, because according to rfc rfc7231 that defines HTTP codes this code refers to a resource that was searched on the server and was not found, so it is not limited to invalid url only.

rfc:

 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.

Already the code 200 informs that the request was met successfully, IE, should its used when found the resource being sought.

rfc

The 200 (OK) status code indicates that the request has succeeded.

Sources: Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content

  • 1

    As I said, the status 200 informs that everything happened OK. And, as much as it did not bring results, the request was OK, it worked as expected. In the rfc7231, we have: 404 Not Found = The server has not found Anything matching the Request-URI.

  • 1

    Hi @Valdeirpsr, the link you consulted ended up misleading you, I believe that google probably, this link you put actually refers to RFC2616, it was suspended and replaced by Rfcs (7230-7237), query the link https://www.W3.org/Protocols/rfc2616/rfc2616.html ai has this information. Thank you

  • 1

    I would only use 404 if name if it is a unique identifier, if it is a search it should be 200, because both the endpoint and the search are correct, it just doesn’t work. I don’t think semantic an error return for a request that was made correctly.

4

I believe that Status 404 (Not Found) is more suitable for features that, in fact, are not found, but were expected to be. If it is a search, of the type may or may not be found, I would use the 204, as it signals that the search did not return results. An empty array: [] would be interesting, for being self-explanatory.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.