What is the appropriate HTTP status code for a null or missing object attribute?

9.9k views Asked by At

Let's say we have an API with a route /foo/<id> that represents an instance of an object like this:

class Foo:
    bar: Optional[Bar]
    name: str
    ...

class Bar:
    ...

(Example in Python just because it's convenient, this is about the HTTP layer rather than the application logic.)

We want to expose full serialized Foo instances (which may have many other attributes) under /foo/<id>, but, for the sake of efficiency, we also want to expose /foo/<id>/bar to give us just the .bar attribute of the given Foo.

It feels strange to me to use 404 as the status response when bar is None here, since that's the same status code you'd get if you requested some arbitrarily incorrect route like /random/gibberish, too; if we were to have automatic handling of 404 status in our client-side layer, it would be misinterpreting this with likely explanations such as "we forgot to log in" or "the client-side URL routing was wrong".

However, 200 with a response-body of null (if we're serializing using JSON) feels odd as well, because the presence or absence of the entity at the given endpoint is usually communicated via a status rather than in-line in the body. Would 204 with an empty response-body be the right thing to say here? Is a 404 the right way to go, and if so, what's the right way for the server to communicate nuances like "but that was a totally expected and correct route" or "actually the foo-ID you specified was incorrect, this isn't missing because the attribute was un-set".

What are the advantages and disadvantages of representing the missing-ness of this attribute in different ways?

3

There are 3 answers

3
jayofdoom On BEST ANSWER

I wonder if you could more clearly articulate why a 200 with a null response body is odd. I think it communicates exactly what you want, as long as you're not trying to differentiate between a given Foo not having a bar (e.g. Foo.has_key?(bar)) and Foo having a bar explicitly set to null.

1
swizzard On

Of 404, https://developer.mozilla.com says,

In an API, this can also mean that the endpoint is valid but the resource itself does not exist.

so I think it's acceptable. 204 doesn't strike me as particularly outlandish in this situation, but is more commonly associated (IME, at least) with DELETEs (and occasionally PUTs/POSTs that don't return results.)

1
Thuita Wachira On

I also struggle a lot with this because:

  1. 404 can point to a non existent url, or a path that is acceptable but the particular referenced resource does not exist. I have also used it to error out on request body's that carry identifiers that are non existent.

  2. A lot of people shoe-horn these errors into the bad request (400) error code which is somewhat acceptable but also a cop out. (Literally anything the server did not process successfully can be classified as a bad request, if you think about it)

  3. With 2(above) in mind, a 400 with some helpful message body is sometimes used to wash out the guilt of not committing outrightly to a 404, but this demands some parsing expectations on the client's side, which is not always nice. Also returning a 400 which, according to this is kind of gaslighting the client, because 400 errors are supposed to be the client's fault entirely with regard to the structure of the request, not because the client asked for something not in your db.

400 Bad Request response status code indicates that the server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).

  1. The general feeling is that 200 means all is good, and therefore there's always a tacit expectation the response will always contain some form of body, not null.(Right??) I wouldn't encourage using a 200 for these situations. While 204's don't carry the responsibility having to carry a response body, they also sort of convey the message that "something worked", which is not the message you want to send here, right?

What I'm trying to say? Thoughtful API design is hard.