Should a RESTful API return 404 for arrays of objects? - rest

Lets say there's a Product with Orders. If you ask for /products/product_id, it will return a 404 if product_id doesn't exist. But should /products/product_id/orders return a 404 if no orders exist for this product or should it return an empty array?

I would return an empty collection. A product with zero orders is a completely valid concept, so the existence of an empty orders collection makes more sense than a 404 which would infer that this product does not have a orders collection.

You really should do only one of two things
Either Return a 200 (OK) status code, and an empty array in the body.
Or Return a 204 (NO CONTENT) status code and NO response body.
To me, option 2 seems more technically correct and keeping in line with REST and HTTP principles.
However, option 1 seems more efficient for the client - because the client does not need extra logic to differentiate between two (success) status codes. Since it knows that it will always receive an array, it simply has to check for whether it got none, one, or many items and process it appropriately

Do not return arrays. Return an object in any case, like
{
offset: 30,
limit: 10,
arr: []
}
it allows you to add metadata (for pagination or smth else)
usually with http status code: 200
Also, this is conventional web API behavior, driven by security concerns:
https://cheatsheetseries.owasp.org/cheatsheets/AJAX_Security_Cheat_Sheet.html#always-return-json-with-an-object-on-the-outside

In my opinion:
We're talking http status values here, and should be of a higher level of giving responses.
One should see this in layers of delegates. Like when your api is not able to answer a request, in case the api call itself is not available, then you could reply with a 404.
But when your call exists, and it could reply with a collection of data, but its an empty collection, you could return just a http 200, with an empty result.
I would use http status values to give an indication on the request validation, and not directly make it dependent on the content in the deeper api layers.
Or one could strictly follow protocols found on the net, but nobody follows them...

Related

What is the proper response status for a REST API GET returning no content?

I have an endpoint like so:
GET /api/customer/primary
If a primary customer exists, I return something like
{
name: "customerName"
}
But what if I send a GET and a primary customer doesn't exist?
Is it better to send a 200 OK with an empty JSON {}
Or is better to only send a 204 No Content?
404 is the appropriate status code for this. You're trying to represent a 'primary customer' as a resource, but in some cases this relationship doesn't exists. This situation is pretty clear, it should be a 404 for GET requests.
This is a perfectly acceptable way to communicate this. A 404 might signal a client that the resource doesn't exist yet, and perhaps that it can be created with PUT.
204 No Content has a specific meaning, and doesn't make that much sense for your case. 204 is not just meant to signal there's not going to be response body (Content-Length: 0 can do that), but it has a more specific application for hypermedia applications. Specifically, it signals that when a user performs an action that results in the 204, the view shouldn't refresh. This makes sense for for example an "Update" operation where a user can occasionally save their progress while working on a document. Contrast to 205 Reset Content, which signals that the 'view' should reset so (perhaps) a new document can be created from scratch.
Most applications don't go this far. Frankly, I haven't seen a single one. Given that, returning 200 with Content-Length: 0 or 204 No Content is an almost completely irrelevant discussion. The HTTP specification certainly doesn't forbid 200 OK with Content-Length: 0.
That was a bit of a tangent. To conclude, 404 signals this 'thing' doesn't exist, and that's appropriate here. There's no multiple interpretations. There's the people who wrote the specifications, those who read them well and on the other side of the discussion the people who are wrong.
But what if I send a GET and a primary customer doesn't exist?
Is it better to send a 200 OK with an empty JSON {}
Or is better to only send a 204 No Content?
If I'm interpreting your question correctly, you aren't really asking about status codes, but rather what kind of schema should you be using to manage the different cases in your API.
For cases like REST, where the two ends of the conversation are not necessarily controlled by the same organization and same release cycle, you may need to consider that one side of the conversation is using a more recent schema version than the other.
So how is that going to be possible? The best treatments I have seen focus on designing schema for extension - new fields are optional, and have documented semantics for how they should be understood if a field is absent.
From that perspective
{}
Doesn't look like a representation of a missing object - it looks like a representation of an object with default values for all of the optional fields.
It might be that what you want is something like Maybe or Option - where instead of promising to send back an object or not, you are promising to send back a collection of zero or one object. Collections I would normally expected to be represented in JSON as a array, rather than an object.
[]
Now, with that idea in pocket, I think it's reasonable to decide that you are returning a representation of a Maybe, where the representation of None is zero bytes long, and the representation of Some(object) is the JSON representation of the object.
So in that design 204 when returning None makes a lot of sense, and you can promise that if a successful response returns a body, that there is really something there.
There's a trade off here - the list form allows consumers to always parse the data, but they have to do that even when a None is sent. On the other hand, using the empty representation for None saves a parse, but requires that the consumer be paying attention to the content length.
So, looking back to your two proposals, I would expect that using 204 is going to be the more successful long term approach.
Another possibility would be to return the null primitive type when you want to express that there is no object available. This would go with a 200 response, because the content length would be four bytes long.
null
HTTP 404 status's text ("Not Found") is the closest to the situation, But:
The first digit of the Status-Code defines the class of response. The
last two digits do not have any categorization role. There are 5
values for the first digit:
1xx: Informational - Request received, continuing process
2xx: Success - The action was successfully received,
understood, and accepted
3xx: Redirection - Further action must be taken in order to
complete the request
4xx: Client Error - The request contains bad syntax or cannot
be fulfilled
5xx: Server Error - The server failed to fulfill an apparently
valid request
(reference)
In practice, 4xx recognized as an error and it is likely some alerts will rise from network / security / logging infrastructure
204 semantic indicate that the server has successfully fulfilled a request and there is no additional content to send - not exactly what happening.
A common use case is to return 204 as a result of a PUT request, updating the resource.
Therefore I would recommend using either:
HTTP 200 with an empty object / array
like you suggested.
HTTP 200 returning a null object, e.g.:
"none" (valid JSON)
or
{
"name": "NO_PRIMARY_CUSTOMER"
}
(implementation of such a null object depends on your specific system behavior with the returned data)
Custom HTTP 2xx code with an empty result
Less common, but still workable alternative is to return a custom HTTP code within the 2xx range (e.g. HTTP 230) with an empty result.
This option should be used with extra caution or even avoided if the API is exposed to a wide audience that may use unknown tools to access / monitor the API.

What should be the response of GET for multiple requested resources with some invalid ids?

what should be the response to a request to
http://localhost:8080/users/1,2,3 when the system doesn't have a user with id 3?
When all users are present I return a 200 response code with all user objects in the response body. When the user requests a single missing user I return a 404 with an error message in the body.
However, what should be the body and status code for a mix between valid and missing ids?
I assume that you want to follow REST API principles. In order to keep clear api design you should rather use query string for filtering
http://localhost:8080/users?id=1,2,3
Then you won't have such dilemmas - you can return just only users with id contained in provided value list and 200 status code (even if list is empty). This endpoint in general
http://localhost:8080/users/{id}
should be reserved for requesting single resource (user) by providing primary key.
What you are requesting there is a collection. The request essentially reads: "give me all users whose ID is in {1, 2, 3}." A subset of those users (let's say there is no user yet with the ID 3) would still be a successful operation, which is asking for a 200 (OK).
If you are overly concerned by this, there's still the possibility to redirect the client via 303 (See Other) to a resource representation without the offending elements.
If all of the IDs are invalid, things get a bit tricky. One may be tempted to simply return a 404 (Not Found), but strictly speaking that were not correct:
The 404 status code indicates that the origin server did not find a current representation for the target resource
Indeed, there is one: The empty set. From a programmatic standpoint, it may indeed be easier to just return that instead of throwing an error. This relies on clients being able to process empty sets/documents.
The RFC grants you the freedom to go either way:
[…] the origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
So if you wish to hide the existence of an empty set, it's okay. It bears mentioning that a set containing nothing is not nothing itself ;)
I would recommend not to offer the method in the first place, but rather force the user of your APIto make three separate requests and return unambiguous responses (two 200s for users 1 and 2 and 404 for user 3). Additionally, the API could offer a get method that responds with all available user ids or such (depends on your system).
Alternatively, if that's not an option, I guess, you have two options:
Return 404 as soon as one user is not found, which technically is more accurate in my opinion. I mean, the request was for 1, 2 AND 3, which was not found.
Return 200 with users 1 and 2, and null, which probably is the most useful for your scenario.

Rest service returns 404

What is the best practice in return codes if a call to a rest service executes a database query, no results are found and it returns.
Should this be a 404 or a 200 with a message stating no records?
The URL has resolved correctly and no server error has occurred just that there are no records returned.
EDIT:
Example url is:
http://localhost/app/pr_xyz/1234
Used to retrieve a list of xyz that belong to the existing user 1234. The user id 1234 has already been retrieved and is known to exist in the database. This URL (pr_xyz) is just to retrieve a list of xyz that belong to that user.
The relationship is 1 user to 0 or many xyz.
In this case the existing user has no xyz. Should this be a 404 or 200 with meaningful message.
Also I have no control over the URL.
Agree with #Satya, it should be a 200, but we can arrive at the answer by working backwards.
So, we start with the full list of HTTP status codes.. Start from the bottom.
Is it a server error? No? Then it's not a 5xx
Is it a client error? Maybe? Perhaps it's not a 4xx
It's obviously not a redirect, so it's not a 3xx.
Is it a successful call? Perhaps.
Are you returning a provisional response? No, it's not a 1xx either.
So by process of elimination, which are looking at the 2xx codes. Exactly which would be a good fit depends on the semantics of your application.
Since, this is not a DELETE call, then I probably wouldn't use 204 No Content, which is probably the only good alternative. It's not that there's no content.
There is content: "0 results found". Google doesn't show you a blank page when there are no search results.
So we arrive at 200, as well as returning a meaningful body. If you were returning raw results, then you might want to consider wrapping them in a search-results object to provide some meta-data.
Ah! So wait, what if instead of search results, you are indicating a collection of RESTful resources?
GET /items
In this case, I would still return a 200 with a body that says there are no items.
What if, you were trying to retrieve a particular resource?
GET /items/1234
In this case, yes, you want to imply that item 1234 does not exist, and you should return a 404.

HTTP 200 or 404 for empty list?

I know this is a fairly common question, but I haven't found an answer that satisfies me.
I've been using django rest framework for a while now, but this is mostly irrelevant other than the example given. Its default behaviour is to return an HTTP 200 with an empty list resource when accessing a route with an empty list of items.
E.g.: if we had a route such as /articles/ to access a list of articles but it contained no items we would get a response like the following json:
{"count":0, "next":null, "previous":null, "items": []}
Which is perfectly fine. We found the resource we were looking for at /articles/, it just happens to have no items in it.
If we access the route /articles/?page=1, we get the exact same response.
So far so good. Now we try to access /articles/?page=2, and the response code changes. Now get get a 404 as if the resource could not be found with an error message saying that the page contains no results. Which is the same case as with ?page=1...
I was perfectly ok with this behaviour, but today I started questioning this design. How is the ?page=1 case different than ?page=2 ? And what's more, how could you tell if the request was "valid" when issuing a HEAD request? Valid in the sense of containing any results.
This could be useful in cases like filtering a list checking the availability of a certain field (for example, issuing a HEAD request to /users/?username=ted).
A 200 response would clearly mean the request was understood and items were found.
A 404 would mean the request was understood, but no items were found at that location/URI (AFAIK the query parameters are also part of the URI)
In case the request could not be understood a 400 would be returned for syntactic errors, and a 422 for semantic errors.
Is this a good design? Why do most people seem to disagree with it and what drawbacks are there in it?
I would go for 200 because the resource is articles.
While querying for ted in users the same applies, users is the resource and as long it is there, a 200 is okay from my point of view.
If you would GET users/ted a 404 would be as good as a 410 (GONE) if a user named ted was there in the past (may better applies to articles than users).
Because we are ok with an empty page1, not ok with an empty page2.
This is driven by the UI consideration (page1 must exist!), nevertheless, it decides the response code.
This really boils down to the "null vs empty collection" argument. The cases for null are also cases for HTTP 404, and the cases for an empty collection are also cases for HTTP 200.
if we had a route such as /articles/ to access a list of articles but it contained no items
Assuming this is a global list of articles, i.e:
http://mywebsite/articles
then this response can never be null, and therefore should never be a 404. The global list of articles always exists, and therefore the collection is always not-null, regardless of whether it contains elements or not.
A simple example here is thinking of a SQL query. If a table exists, even if it's empty, a query will return a result (be it empty or not), so use 200. If the table itself does not exist, you get a query error, so 404.
But if the articles are contained within another resource, e.g. their author:
http://mywebsite/authors/johndoe/articles
Now we get to the part where null (and thus 404) is meaningfully possible.
If johndoe exists and has articles, you return a non-empty list
If johndoe exists and does not have articles, you return an empty list and HTTP status 200
If johndoe does not exist, then you return null and HTTP status 404
This communicates the correct response to the user. 200 reveals that the data was correctly fetched, whereas 404 reveals that the requested resource simply does not exist.
Note that this is slightly different when referring to a specific article instead of a list. When returning a specific resource (or not), instead of a list, 404 is the only correct HTTP status for a 'no item' response.
http://mywebsite/article/1
Here, you either return the article or null.
http://mywebsite/authors/johndoe/articles/1
Here, you return 404 when either author johndoe or article 1 does not exist.
200 simply means the request has succeeded. The information returned with the response is dependent on the method used in the request, for example:
GET an entity corresponding to the requested resource is sent in the response;
HEAD the entity-header fields corresponding to the requested resource are sent in the response without any message-body;
POST an entity describing or containing the result of the action;
TRACE an entity containing the request message as received by the end server.
404 - The server has not found anything matching the Request-URI - In this case I think it means we did not find the page that articles would have been listed on.
So 200 it is. - but perhaps understand what is being returned and format a message that 0 article have been returned.

REST status code 204 on paginated result

I am designing a REST like API for paginated data retrieval of a YUI-based client.
The REST URL looks like this for a GET request:
/app/catalog/data?startIndex=<int>&results=<int>&sort=<sting>&dir=<string>
All parameters are optional, i.e. if no parameters are given, all data from DB will be dumped.
Now say that there are only 1000 records in the database. Following reqeust is made:
/app/catalog/data?startIndex=1100&results=25
What status code should I return if the paginated result from the database remains empty though the request was fine?! I can't decide whether this is 204 or 404.
The produced media types are JSON and CSV.
I would say 204 is most appropriate. The request was successful, just with no results.
10.2.5 204 No Content
The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation.
Sounds exactly like the case.
I can't decide whether this is 204 or 404.
Neither. Just return 200 with an empty result (empty XML document or JSON array, whatever you use). Typically I use REST services with paginated views so along with results page I return total number of records. This will help clients to realize the mistake. But technically it is nothing wrong.
Use 204 for DELETE operations (there's really no content to return) and for PUT.
BTW (bold mine):
if no parameters are given, all data from DB will be dumped
Believe, you don't want to do this...
What format do you normally return your results in? I'd be inclined to make this 204 or even 200 returning an empty list.
HTTP 204 in pagination response is not factible because of the payload. When paginating you should return pagination information like, items returned, total items, offset, etc. which makes no sense with HTTP 204.
HTTP 204 is useful on resource updates (ie PUT) when you want to explicitly say that the resource does not need to be fetched again (GET). For example, resources that have calculated fields and require a refresh of the view after every update, fetching those calculated fields from the server. Therefore, the 204 status code has specific use cases and must be designed and documented.
I would use one of:
HTTP 200 with count=0 and no items in the returned list.
HTTP 400 because invoker asked for an url that is invalid
HTTP 404 because items to return are not found
Choose the one that best suits the way your API works.
I think it's safe to return an error (4xx + error info) in this situation because the offset can be exceeded by one of these assumptions:
A coding error
Invoker is not fetching data from begining (no fresh state)
Invoker ignored pagination data (present on each response)
You are not using total field in the response (which is optional because there are some situations where you can not count all items or simply it's very expensive counting them). In this case, if your last page has the same number of items (count) as the number of items asked for in the request (limit), there is no way to know that this is the last page, so you try another one. In that last request you will get a count=0 in the response and you can stop asking for pages. This case makes it fair to return a 200 code also because the programmer did exactly what you asked for in the API documentation.