JSON API – When to Return a 404 Not Found

apijsonrest

I'm working on a REST api following the JSON api specification and I'm struggling with the "no data" responses (described here).

A server MUST respond with 404 Not Found when processing a request to
fetch a single resource that does not exist, except when the request
warrants a 200 OK response with null as the primary data (as described
above).

The "described above" refers to the previous section of the specification :

A server MUST respond to a successful request to fetch an individual
resource with a resource object or null provided as the response
document's primary data.

null is only an appropriate response when the requested URL is one
that might correspond to a single resource, but doesn't currently.

I don't understand when I need to return a HTTP 404 Not Found and when I need with HTTP 200 OK with {"data":null}.

For example, if I have the following URL :

http://example.org/users/52

This URL is correct, but the User referenced by the ID 52 doesn't exist.What is the correct response ? A 404 or a 200 data: null ?

Best Answer

If the user 52 doesn't exist, return HTTP 404. Returning HTTP 200 is misleading.

Think about it from the point of view of the client. Would the following dialog make sense to you?

Client: please, I want to know something about user 52.
Server: of course (HTTP 200). What do you want to know?
Client: I want to know the basic information about the user.
Server: There is no information whatsoever about this user; I don't even know what are you talking about.

The case where you could use HTTP 200 with null is when you don't have information about a part of the entry being requested. Imagine a case where the users have a purchase history, unless they registered very recently and haven't been approved yet (and cannot order anything). For an ordinary, approved user, the response will be:

HTTP/1.1 200 OK

{
    "id": 51,
    "name": "Laura Norman",
    "purchase-history": [
        { ... },
        ...
    ]
}

Instead, the user 52 doesn't have a purchase history:

HTTP/1.1 200 OK

{
    "id": 52,
    "name": "David Johnson",
    "purchase-history": null
}

This is semantically different from an empty sequence. "purchase-history": [] means that the user has a history, but haven't purchased anything yet. A null has a very different meaning.