What is the proper REST response code for a valid

2019-01-05 06:54发布

For example you run a GET request for users/9 but there is no user with id #9. Which is the best response code?

  • 200 OK
  • 202 Accepted
  • 204 No Content
  • 400 Bad Request
  • 404 Not Found

13条回答
【Aperson】
2楼-- · 2019-01-05 07:31

What the existing answers do not elaborate on is that it makes a difference whether you use path parameters or query parameters.

  • In case of path parameters, the parameter is part of the resource path. In case of /users/9, the response should be 404 because that resource was not found. /users/9 is the resource, and the result is unary, or an error, it doesn't exist. This is not a monad.
  • In case of query parameters, the parameter is not part of the resource path. In case of /users?id=9, the response should be 204 because the resource /users was found but it could not return any data. The resource /users exists and the result is n-ary, it exists even if it is empty. If id is unique, this is a monad.

Whether to use path parameters or query parameters depends on the use case. I prefer path parameters for mandatory, normative, or identifying arguments and query parameters for optional, non-normative, or attributing arguments (like paging, collation locale and stuff). In a REST API, I would use /users/9 not /users?id=9 especially because of the possible nesting to get "child records" like /users/9/ssh-keys/0 to get the first public ssh key or /users/9/address/2 to get the third postal address.

I prefer using 404. Here's why:

  • Calls for unary (1 result) and n-ary (n results) methods should not vary for no good reason. I like to have the same response codes if possible. The number of expected results is of course a difference, say, you expect the body to be an object (unary) or an array of objects (n-ary).
  • For n-ary, I would return an array, and in case there are not results, I would not return no set (no document), I would return an empty set (empty document, like empty array in JSON or empty element in XML). That is, it's still 200 but with zero records. There's no reason to put this information on the wire other than in the body.
  • 204 is like a void method. I would not use it for GET, only for POST, PUT, and DELETE. I make an exception in case of GET where the identifiers are query parameters not path parameters.
  • Not finding the record is like NoSuchElementException, ArrayIndexOutOfBoundsException or something like that, caused by the client using an id that doesn't exist, so, it's a client error.
  • From a code perspective, getting 204 means an additional branch in the code that could be avoided. It complicates client code, and in some cases it also complicates server code (depending on whether you use entity/model monads or plain entities/models; and I strongly recommend staying away from entity/model monads, it can lead to nasty bugs where because of the monad you think an operation is successful and return 200 or 204 when you should actually have returned something else).
  • Client code is easier to write and understand if 2xx means the server did what the client requested, and 4xx means the server didn't do what the client requested and it's the client's fault. Not giving the client the record that the client requested by id is the client's fault, because the client requested an id that doesn't exist.

Last but not least: Consistency

  • GET /users/9
  • PUT /users/9 and DELETE /users/9

PUT /users/9 and DELETE /users/9 already have to return 204 in case of successful update or deletion. So what should they return in case user 9 didn't exist? It makes no sense having the same situation presented as different status codes depending on the HTTP method used.

Besides, not a normative, but a cultural reason: If 204 is used for GET /users/9 next thing that will happen in the project is that somebody thinks returning 204 is good for n-ary methods. And that complicates client code, because instead of just checking for 2xx and then decoding the body, the client now has to specifically check for 204 and in that case skip decoding the body. Bud what does the client do instead? Create an empty array? Why not have that on the wire, then? If the client creates the empty array, 204 is a form of stupid compression. If the client uses null instead, a whole different can of worms is opened.

查看更多
\"骚年 ilove
3楼-- · 2019-01-05 07:35

TL;DR: Use 404

See This Blog. It explains it very well.

Summary of the blog's comments on 204:

  1. 204 No Content is not terribly useful as a response code for a browser (although according to the HTTP spec browsers do need to understand it as a 'don't change the view' response code).
  2. 204 No Content is however, very useful for ajax web services which may want to indicate success without having to return something. (Especially in cases like DELETE or POSTs that don't require feedback).

The answer, therefore, to your question is use 404 in your case. 204 is a specialized reponse code that you shouldn't often return to a browser in response to a GET.

The other response codes that are even less appropriate than 204 and 404:

  1. 200 should be returned with the body of whatever you successfully fetched. Not appropriate when the entity you're fetching doesn't exist.
  2. 202 is used when the server has begun work on an object but the object isn't fully ready yet. Certainly not the case here. You haven't begun, nor will you begin, construction of user 9 in response to a GET request. That breaks all sorts of rules.
  3. 400 is used in response to a poorly formatted HTTP request (for instance malformed http headers, incorrectly ordered segments, etc). This will almost certainly be handled by whatever framework you're using. You shouldn't have to deal with this unless you're writing your own server from scratch. Edit: Newer RFCs now allow for 400 to be used for semantically invalid requests.

Wikipedia's description of the HTTP status codes are particularly helpful. You can also see the definitions in the HTTP/1.1 RFC2616 document at www.w3.org

查看更多
仙女界的扛把子
4楼-- · 2019-01-05 07:37

At first, I thought a 204 would make sense, but after the discussions, I believe 404 is the only true correct response. Consider the following data:

Users: John, Peter

METHOD  URL                      STATUS  RESPONSE
GET     /users                   200     [John, Peter]
GET     /users/john              200     John
GET     /users/kyle              404     Not found
GET     /users?name=kyle`        200     []
DELETE  /users/john              204     No Content

Some background:

  1. the search returns an array, it just didn't have any matches but it has content: an empty array.

  2. 404 is of course best known for url's that aren't supported by the requested server, but a missing resource is in fact the same.
    Even though /users/:name is matched with users/kyle, the user Kyle is not available resource so a 404 still applies. It isn't a search query, it is a direct reference by a dynamic url, so 404 it is.

Anyway, my two cents :)

查看更多
再贱就再见
5楼-- · 2019-01-05 07:38

To summarize or simplify,

2xx: Optional data: Well formed URI: Criteria is not part of URI: If the criteria is optional that can be specified in @RequestBody and @RequestParam should lead to 2xx. Example: filter by name / status

4xx: Expected data : Not well formed URI : Criteria is part of URI : If the criteria is mandatory that can only be specified in @PathVariable then it should lead to 4xx. Example: lookup by unique id.

Thus for the asked situation: "users/9" would be 4xx (possibly 404) But for "users?name=superman" should be 2xx (possibly 204)

查看更多
Animai°情兽
6楼-- · 2019-01-05 07:39

There are two questions asked. One in the title and one in the example. I think this has partly led to the amount of dispute about which response is appropriate.

The question title asks about empty data. Empty data is still data but is not the same as no data. So this suggests requesting a result set, i.e. a list, perhaps from /users. If a list is empty it is still a list therefore a 204 (No Content) is most appropriate. You have just asked for a list of users and been provided with one, it just happens to have no content.

The example provided instead asks about a specific object, a user, /users/9. If user #9 is not found then no user object is returned. You asked for a specific resource (a user object) and were not given it because it was not found, so a 404 is appropriate.

I think the way to work this out is if you can use the response in the way you would expect without adding any conditional statement, then use a 204 otherwise use a 404.

In my examples I can iterate over an empty list without checking to see if it has content, but I can't display user object data on a null object without breaking something or adding a check to see if it is null.

You could of course return an object using the null object pattern if that suits your needs but that is a discussion for another thread.

查看更多
够拽才男人
7楼-- · 2019-01-05 07:41

I strongly oppose 404 in favour of 204 or 200 with empty data.

The request was received and properly processed - it did trigger application code on the server, thus one cannot really say that it was a client error and thus the whole class of client error codes (4xx) is not fitting.

More importantly, 404 can happen for a number of technical reasons. E.g. the application being temporarily deactivated or uninstalled on the server, proxy connection issues and whatnot. Therefore the client cannot distinguish between a 404 that means "empty result set" and a 404 that means "the service cannot be found, try again later".

This can be fatal: Imagine an accounting service in your company that lists all the employees that are due to an annual bonus. Unfortunately, the one time when it is called it returns a 404. Does that mean that no-one is due for a bonus, or that the application is currently down for a new deployment?

-> For applications that care about the quality of their data, 404 therefore is pretty much a no-go.

Also, many client frameworks respond to a 404 by throwing an exception with no further questions asked. This forces the client developer to catch that exception, to evaluate it, and then to decide based on that whether to log it as an error that is picked up by e.g. a monitoring component or whether to ignore it. That doesn't seem pretty to me either.

The only advantage of 404 over 204 is that it can return a response entity that may contain some information about why the requested resource was not found. But if that really is relevant, then one may also consider using a 200 OK response and design the system in a way that allows for error responses in the payload data. Alternatively, one could use the payload of the 404 response to return structured information to the caller. If he receives e.g. a html page instead of XML or JSON that he can parse, then that is a good indicator that something technical went wrong instead of a "no result" reply that may be valid from the caller's point of view. Or one could use a HTTP response header for that.

Still i would prefer a 204 or 200 with empty response though. That way the status of the technical execution of the request is separated from the logical result of the request. 2xx means "technical execution ok, this is the result, deal with it".

I think in most cases it should be left to the client to decide whether an empty result is acceptable or not. By returning 404 despite of a correct technical execution the client may decide to consider cases to be errors that simply are no errors.

Another quick analogy: Returning 404 for "no result found" is like throwing a DatabaseConnectionException if a SQL query returned no results. It can get the job done, but there are lots of possible technical causes that throw the same exception which then would be mistaken for a valid result.

查看更多
登录 后发表回答