When to Use HTTP Status Code 404 in an API

apihttphttp-response

I am working on a project and after arguing with people at work for about more than a hour. I decided to know what people on stack-exchange might say.

We're writing an API for a system, there is a query that should return a tree of Organization or a tree of Goals.

The tree of Organization is the organization in which the user is present, In other words, this tree should always exists. In the organization, a tree of goal should be always present. (that's where the argument started). In case where the tree doesn't exist, my co-worker decided that it would be right to answer response with status code 200. And then started asking me to fix my code because the application was falling apart when there is no tree.

I'll try to spare flames and fury.

I suggested to raise a 404 error when there is no tree. It would at least let me know that something is wrong. When using 200, I have to add special check to my response in the success callback to handle errors. I'm expecting to receive an object, but I may actually receive an empty response because nothing is found. It sounds totally fair to mark the response as a 404. And then war started and I got the message that I didn't understand HTTP status code schema. So I'm here and asking what's wrong with 404 in this case? I even got the argument "It found nothing, so it's right to return 200". I believe that it's wrong since the tree should be always present. If we found nothing and we are expecting something, it should be a 404.

More info,

I forgot to add the urls that are fetched.

Organizations

/OrgTree/Get

Goals

/GoalTree/GetByDate?versionDate=...
/GoalTree/GetById?versionId=...

My mistake, both parameters are required. If any versionDate that can be parsed to a date is provided, it will return the closes revision. If you enter something in the past, it will return the first revision. If by Id with a id that doesn't exists, I suspect it's going to return an empty response with 200.

Extra

Also, I believe the best answer to the problem is to create default objects when organizations are created, having no tree shouldn't be a valid case and should be seen as an undefined behavior. There is no way an account can be used without both trees. For that reasons, they should be always present.

also I got linked this (one similar but I can't find it)

http://viswaug.files.wordpress.com/2008/11/http-headers-status1.png

Best Answer

When in doubt, consult the documentation. Reviewing the W3C definitions for HTTP Status codes, gives us this:

200 OK - The request has succeeded. The information returned with the response is dependent on the method used in the request.

404 Not Found - The server has not found anything matching the Request-URI.

In the context of your API, it very much depends on how queries are created and how objects are retrieved. But, my interpretation has always been that:

  • If I ask for a particular object, and it exists return 200 code, if it doesn't exist return the correct 404 code.
  • But, if I ask for a set of objects that match a query, a null set is a valid response and I want that returned with a 200 code. The rationale for this is that the query was valid, it succeeded and the query returned nothing.

So in this case you are correct, the service isn't searching for "a specific thing" it is requesting a particular thing, if that thing isn't found say that clearly.

I think Wikipedia puts it best:

200 OK - ... The actual response will depend on the request method used. In a GET request, the response will contain an entity corresponding to the requested resource.

404 Not Found - The requested resource could not be found but may be available again in the future. Subsequent requests by the client are permissible.

Seems pretty clear to me.

Regarding the example requests

/GoalTree/GetByDate?versionDate=...
/GoalTree/GetById?versionId=...

For the format, you said, you always return the nearest revision to that date. It will never not return an object, so it should always be returning 200 OK. Even if this were able to take a date range, and the logic were to return all objects within that timeframe returning 200 OK - 0 Results is ok, as that is what the request was for - the set of things that met that criteria.

However, the latter is different as you are asking for a specific object, presumably unique, with that identity. Returning 200 OK in this case is wrong as the requested resource doesn't exist and is not found.

Regarding choosing status codes

  • 2xx codes Tell a User Agent (UA) that it did the right thing, the request worked. It can keep doing this in the future.
  • 3xx codes Tell a UA what you asked probably used to work, but that thing is now elsewhere. In future the UA might consider just going to the redirect.
  • 4xx codes Tell a UA it did something wrong, the request it constructed isn't proper and shouldn't try it again, without at least some modification.
  • 5xx codes Tell a UA the server is broken somehow. But hey that query could work in the future, so there is no reason not to try it again. (except for 501, which is more of a 400 issue).

You mentioned in a comment using a 5xx code, but your system is working. It was asked a query that doesn't work and needs to communicate that to the UA. No matter how you slice it, this is 4xx territory.

Consider an alien querying our solar system

Alien: Computer, please tell me all planets that humans inhabit.

Computer: 1 result found. Earth

Alien: Computer, please tell me about Earth.

Computer: Earth - Mostly Harmless.

Alien: Computer, please tell me about all planets humans inhabit, outside the asteroid belt.

Computer: 0 results found.

Alien: Computer, please destroy Earth.

Computer: 200 OK.

Alien: Computer, please tell me about Earth.

Computer: 404 - Not Found

Alien: Computer, please tell me all planets that humans inhabit.

Computer: 0 results found.

Alien: Victory for the mighty Irken Empire!