[rest] What is the proper REST response code for a valid request but an empty data?

I'd say, neither is really appropriate. As has been said – e.g. by @anneb, I, too, think that part of the problems arises from using an HTTP response code to transport a status relating to a RESTful service. Anything the REST service has to say about its own processing should be transported by means of REST specific codes.

1

I'd argue that, if the HTTP server finds any service that is ready to answer a request it was sent, it should not respond with an HTTP 404 – in the end, something was found by the server – unless told so explicitly by the service that processes the request.

Let's assume for a moment the following URL: http://example.com/service/return/test.

  • Case A is that the server is “simply looking for the file on the file system“. If it is not present, 404 is correct. The same is true, if it asks some kind of service to deliver exactly this file and that service tells it that nothing of that name exists.
  • In case B, the server does not work with “real” files but actually the request is processed by some other service – e.g. some kind of templating system. Here, the server cannot make any claim about the existence of the resource as it knows nothing about it (unless told by the service handling it).

Without any response from the service explicitly requiring a different behaviour, the HTTP server can only say 3 things:

  • 503 if the service that is supposed to handle the request is not running or responding;
  • 200 otherwise as the HTTP server can actually satisfy the request – no matter what the service will say later;
  • 400 or 404 to indicate that there is no such service (as opposed to “exists but offline”) and nothing else was found.

2

To get back to the question at hand: I think the cleanest approach would be to not use an HTTP any response code at all other than said before. If the service is present and responding, the HTTP code should be 200. The response should contain the status the service returned in a separate header – here, the service can say

  • REST:EMPTY e.g. if it was asked to search for sth. and that research returned empty;
  • REST:NOT FOUND if it was asked specifically for sth. “ID-like” – be that a file name or a resource by ID or entry No. 24, etc. – and that specific resource was not found (usually, one specific resource was requested and not found);
  • REST:INVALID if any part of the request it was sent is not recognized by the service.

(note that I prefixed these with “REST:” on purpose to mark the fact that while these may have the same values or wording as do HTTP response codes, they are sth. completely different)

3

Let's get back to the URL above and inspect case B where service indicates to the HTTP server that it does not handle this request itself but passes it on to SERVICE. HTTP only serves out what it is handed back by SERVICE, it does not know anything about the return/test portion as that is handeled by SERVICE. If that service is running, HTTP should return 200 as it did indeed find something to handle the request.

The status returned by SERVICE (and which, as said above, would like to see in a separate header) depends on what action is actually expected:

  • if return/test asks for a specific resource: if it exists, return it with a status of REST:FOUND; if that resource does not exist, return REST:NOT FOUND; this could be extended to return REST:GONE if we know it once existed and will not return, and REST:MOVED if we know it has gone hollywood
  • if return/test is considered a search or filter-like operation: if the result set is empty, return an empty set in the type requested and a status of REST:EMPTY; a set of results in the type requested and a status of REST:SUCCESS
  • if return/test is not an operation recogized by SERVICE: return REST:ERROR if it is completely wrong (e.g. a typo like retrun/test), or REST:NOT IMPLEMENTED in case it is planned for later.

4

This distinction is a lot cleaner than mixing the two different things up. It will also make debugging easier and processing only slightly more complex, if at all.

  • If an HTTP 404 is returned, the server tells me, “I have no idea what you're talking about”. While the REST portion of my request might be perectly okay, I'm looking for par'Mach in all the wrong places.
  • On the other hand, HTTP 200 and REST:ERR tells me I got the service but did something wrong in my request to the service.
  • From HTTP 200 and REST:EMPTY, I know that I did nothing wrong – right server, the server found the service, right request to the service – but the search result is empty.

Summary

The problem and discussion arises from the fact that HTTP response codes are being used to denote the state of a service whose results are served by HTTP, or to denote sth. that is not in the scope of the HTTP server itself. Due to this discrepancy, the question cannot be answered and all opinions are subject to a lot of discussion.

The state of a request processed by a service and not the HTTP server REALLY SHOULD NOT (RFC 6919) be given by an HTTP response code. The HTTP code SHOULD (RFC 2119) only contain information the HTTP server can give from its own scope: namely, whether the service was found to process the request or not.

Instead, a different way SHOULD be used to tell a consumer about the state of the request to the service that is actually processing the request. My proposal is to do so via a specific header. Ideally, both the name of the header and its contents follow a standard that makes it easy for consumers to work with theses responses.

Examples related to rest

Access blocked by CORS policy: Response to preflight request doesn't pass access control check Returning data from Axios API Access Control Origin Header error using Axios in React Web throwing error in Chrome JSON parse error: Can not construct instance of java.time.LocalDate: no String-argument constructor/factory method to deserialize from String value How to send json data in POST request using C# How to enable CORS in ASP.net Core WebAPI RestClientException: Could not extract response. no suitable HttpMessageConverter found REST API - Use the "Accept: application/json" HTTP Header 'Field required a bean of type that could not be found.' error spring restful API using mongodb MultipartException: Current request is not a multipart request

Examples related to http

Access blocked by CORS policy: Response to preflight request doesn't pass access control check Axios Delete request with body and headers? Read response headers from API response - Angular 5 + TypeScript Android 8: Cleartext HTTP traffic not permitted Angular 4 HttpClient Query Parameters Load json from local file with http.get() in angular 2 Angular 2: How to access an HTTP response body? What is HTTP "Host" header? Golang read request body Angular 2 - Checking for server errors from subscribe

Examples related to api-design

When do I use path params vs. query params in a RESTful API? What are best practices for REST nested resources? API pagination best practices What is the proper REST response code for a valid request but an empty data?