How to handle GET requests when there are no matching resources? - rest

Given a resource called pets, there should be two ways of retrieving the resource with the pet endpoint:
GET .../pets/{petId} - retrieve a pet by its id
GET .../pets/ - retrieves all pets
How should the API respond when the database doesn't find anything at the resource path?
My assumption is that:
GET .../pets/{petId} -> results in a HTTP 404 (Not found / error). This is because the API has been requested to find a specific resource (petId), it is an error as that pet id doesn't exist.
GET .../pets/ -> returns an empty array [] with HTTP 200 (ok). This is because the API has been requested to find all pet resources, the database just happens to not contain any.
Is this the right approach?
Is there any documentation / resources that explains what is meant to happen in this scnario? (I couldn't find anything using search)

Related

Resources in APIRestful

I have read several things about API's but there is something that is not clear to me on the subject of how to structure the resources. I will give you an easy but illustrative example. We imagine we have this relationship:
|Clients| (1:1) ------<>----- (0:M) |Orders| (1:1) ------<>------ (1:1) |Statuses|
A client can have zero or many orders and each order has a status.
The question comes when making resources, the resources that are clear are as follows:
GET /clients (get a list)
GET /clients/10 (get detail of one client)
POST /clients (create a client passing data by BODY)
(there could be more like the PUT but to simplify the example I simplify.)
The question is, to get the Orders from a Customer such as the resource?
GET /clientes/10/orders
Or in place:
GET /orders?id_cliente=10
The same to get the detail of an Order, what would it be like?
GET /clientes/10/orders/10
Or it would simply make sense to do this (which would also show the information of the State that you have):
GET /orders/10
Or when you want to delete an order:
DELETE /orders/10
or
DELETE /clientes/10/orders/10
And to create an Order, should the Customer always exist or could a Order and a Customer be created at the same time with the following resource? For example, a Customer not registered when making a purchase will place the Order and register at the same time)
POST /orders
Passing the Customer data in the BODY to it as the Order data would go. First the Customer would be created and then the Order.
If there is anyone who knows what all the valid resources of the sample relationship would look like, it would be good to share them. I don't want to get into paginate topics or other topics that are also important in an API. Only in the matter of resources.
To resolve you confusion, you can just ask yourself the following questions.
Does my resource have a unique resource id? - There should not be multiple resource elements pointing to a same resource.
Whether child resource can exist without the parent? - If it can exist, then it should not be considered as a child resource, but has to be concluded as individual resources.
In your case, according to the above, it is clear that the clients resource is a parent of orders resource. So the API endpoints must be,
/clients (GET) - get all clients
/clients/$client_id (GET) - get a client
/clients/$client_id/orders (GET) - get all orders of the particular client
/clients/$client_id/orders (POST) - create new order for the client
/clients/$client_id/orders/$order_id (PUT) - Modify the particular order for the client
/clients/$client_id/orders/$order_id (DELETE) - Delete the particular order for the client
And for your last question on creating a parent resource when a child resource create api called,
Refer my answer
Note : Sorting, filtering, limits and pagination can be supported using query parameters in your APIs.

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.

RESTful API: What to do when there is nothing to return

From what I understand about RESTful APIs:
If I'm asking for an ID that doesn't exist (for example /users/999/posts where user 999 doesn't exist), it should return a 404 status code.
If I'm asking for a list of object, using valid IDs, but there is nothing to return, it should return 200 status code with empty array (for example /users/999/posts where user 999 exists but never posted anything)
Questions I've seen here are usually about those two cases.
Now my question is about when I have no data, I'm using valid IDs, but I'm supposed to return an object instead of a list.
For example, let's assume that for some reason I don't want to always return the user's address when I ask for /users/999. I have this different route: /users/999/address which returns an address object.
What should be returned if that user doesn't have any address? An empty object {} ? 404 status code? 204 status code?
I would think an empty object to be consistent?
Googling, I found this
saying:
The call to return the leagues or teams for a given summoner ID will now return a 404 instead of an empty object. This behavior is the correct RESTful behavior when the requested resource (i.e., leagues or teams) doesn’t exist.
So I'm a bit confused as to what the proper RESTful behaviour should be.
Thanks!
I think a 404 should result from requesting a non-existing address. Indeed, if the address resource does not exist, and the client asks for it (because of an erroneous knowledge on the resource state), the client is making a mistake.
Regarding your point about discovering that a given user has an associated address or not, I would explicit the relationship by using a hypermedia control form the client resource to the address resource, as dictated by the HATEOAS constraint.
Moreover, the address resource is a weak entity w.r.t. the correspoding user. Hence, it is makes sense to return 404 for the two cases. You can still take advantage of the HTTP entity body to better explain what happened.
Think about it from the consumer's point of view, would they rather use the same code when there are no addresses, or have to write a special case for no addresses?
I return an empty collection because it's less work for consumers (and for the REST service, but that's a bonus).
If the request was /users/999/addresses and user 999 didn't exist I'd return a 404.
EDIT: If /users/999/address is the canonical address for the resource (that is it's incorrect to say /users/999/address/1) then I'd return a 404 because the user requested a specific and precise thing.

RESTful API - Once-writeable resource

What is the idiomatic way to represent a once-writeable resource in a RESTful API (in HTTP)? In CRUD terms it should be possible to create the resource but to disallow updates?
EDIT:
Just to add the clarification in the comment on Rosenheimer's answer below. I'd like to allow the client to specify the URL rather than have it generated by a POST handler.
If the resource doesn't exist before (that means "once-writable" actually is "creation" of the resource) then it would be easy to just call the parent for a POST, like this: POST example.com/Resources to send the resource.
Later, do not allow either PUT or PATCH to the specific resource at example.com/Resources/123 where 123 would be the identifier of the resource.
So the resource can be written once but can not be changed later.
I think the correct would be to accept PUT method for the first time resource is saved and return 409 Conflict HTTP status code on any subsequent attempt to update already existing resource.
You could use the HTTP status 405 Method Not Allowed or 403 Forbidden to forbid subsequent update.
Some use POST for resource creation:
# C of CRUD
POST ./phones -> 200 OK with the id of the object created
# R or CRUD
GET ./phones/{id}
# U of CRUD
PATCH/PUT ./phones/{id}
# D of CRUD
DELETE ./phones/{id}
Some may use PUT for object creation but the issue of using PUT is that the method have 2 meaning for the client.

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.