Use of HTTP 204 vs 200 vs 404 to safely signal that a resource doesn't exist - rest

In my REST API I have the normal CRUD endpoints for some resources.
If I do a GET /items/42 and there is no such item, the normal behaviour would be to return a 404 NOT FOUND.
However, one scenario concerns me. In this scenario, a client needs to check if a resource (which is implicitly idenfitied by a token) exists, and if not, create it. So, the client would try to retrieve the resource, and if a 404 is received the client application would display the UI necessary for creating the item, and then proceed to POSTing the new resource. In a way, this is a special kind of resource, because since its ID is derived from other parameters, it's known even before creation. As an example, consider a user sign-up procedure; the client would ask "Do I exist? If no -> register me".
My concern is really whether I ever need to worry about "spurious" 404:s? Considering a server is usually surrounded by API gateways, reverse proxies and such, is there any risk that a 404 NOT FOUND could be produced by a surrounding entity due to some temporary error not related to the REST server itself? If so, it could trick the client into believing that the item is not created yet, and that it should now be created. Even if the resulting POST request to create the item would fail because the item already exists, this isn't very nice because the user may have entered data etc for no reason.
Is this a problem to take into account or just overly paranoid? I guess if clients can't trust a 404 to be idempotent (until the resource is created, of course), many other issues arise. Is there any actual situation where an API gateway or similar would report a 404 on its own?
If this is a valid scenario, do I need a "safer", more explicit response saying that the request definetely succeeded but the resource wasn't found, such as responding with a 200 OK with an empty JSON body or a {isRegistered: false}, a 204 NO CONTENT, or similar? This opens up for other strange things - if a request for a resource that doesn't exist would respond with a 200 accompanied by an empty body, perhaps creation of the item would be a PUT rather than a POST, etc? This seems like a can of worms... It all boils down to "Does a 404 guarantee that the given resource doesn't exist?".

404 is pretty unambiguous : the resource wasn't found and it's a client error (4xx). Normally, server-side errors (5xx) can't interfere and create spurious 404's here.
As an alternative, if the resource to be created is linked to another resource in a unique way, you could use OPTIONS to ask the server if it already exists.
For instance :
OPTIONS /visitors/7883930/user-account
=> Allow: POST,OPTIONS (doesn't exist)
=> Allow: GET,OPTIONS (exists)
The key here is to have a URI that allows accessing the resource without knowing its ID. It is not always possible though.

Related

Would a 404 be acceptable for a DELETE method being called on a non-existent URL?

I am pretty new to the RESTful world, and at the moment I'm debating whether when calling a delete method on a URL that doesn't exist, whether a 404 Resource Not Found should be returned. At the moment, the code returns a 200 OK code, but this doesn't inform a user that what they wanted to do wasn't possible.
I have looked online and on here, and a lot of people have divided opinions on the matter, with HTTP having no standards on return codes.
(I'm thinking in a scenario where someone wants to delete something but through something like a typo, deletes an invalid resource but through there being no error code returned, isn't informed that the delete was unsuccessful, and doesn't realise the mistake.)
I would return the 404 and allow the front-end developer to decide how to handle the situation. As a front-end developer if my user attempted to delete a resource that did not exist, I would like to handle that situation. It could be that the resource was deleted by another user between the time that I found the resource and the present. On the other hand it could be that there was a typo like you said.
But regardless, I would like to know if the user is attempting to delete a resource that no longer exists so that I may handle the situation appropriately.
But this situation depends on the type of application you are constructing. For example, you may want to return a 410 in the case that another user deleted the resource in the last 5 minutes, then return a 404 for all non-existent URLs. But once again, I would only expect a 200 to be returned if something was actually deleted.
SharePoint REST follows this pattern.

Appropriate HTTP status for a PUTting a read-only entity

What is the appropriate HTTP response code when a client tries to PUT to an entity that is currently read only by nature?
A toy example is a product shipment. Before the shipment is sent, the details (address, products, quantities) can be changed (e.g. with a PUT request). However, as soon as the shipment is sent, any PUT should fail, even if the request format and syntax are correct.
It's possible that the client doesn't know that the shipment has been sent, so it's not a "careless" error on the client side.
400 doesn't seem appropriate, because the input is well formed and the syntax is correct.
405 seems like a good fit. Is this a common response in this case?
403 seems to imply authorization has been revoked, which could be misleading.
422 seems to fit well, but its use seems discouraged if you don't provide WebDAV capabilities (which we don't).
500 makes it sound like someone tripped over a cable, though I hear some developers/frameworks use this status in this case.
Is there a standard practice for this case? What is least likely to cause confusion for the API user (developer) and the end user (person using the UI)?
I would look at 405 Method Not Allowed. It is defined like this:
The 405 (Method Not Allowed) status code indicates that the method
received in the request-line is known by the origin server but not
supported by the target resource. The origin server MUST generate an
Allow header field in a 405 response containing a list of the target
resource's currently supported methods.
Your server understands the request perfectly, but it no longer supports writing. In addition, the requirement to return the client the list of supported methods sounds clean.
As an added bonus, the 405 response is cacheable by default, which could make sense in your case.
Another viable alternative is 409 Conflict:
The 409 (Conflict) status code indicates that the request could not be
completed due to a conflict with the current state of the target
resource.
Arguably the order changed state, in such a way modifying it is no longer possible. Note however that:
This code is used in situations where the user might be
able to resolve the conflict and resubmit the request.
…so I would tend toward the other one.

POSTing to a Single Item vs. Collection (REST API)

Say I have a REST API with endpoint /api/users/. POSTing a user to that endpoint would create a new user and add it to the existing collection, give the user a unique ID so that you can work with it. If I make a GET /api/users/1, this should return me the created user with id: 1. My question is what should be the case for POSTing to a single item instead. For POSTing to a collection, you should return 201 Created if the resource was created, or a 409 Conflict if the resource already exists. What is the best practice for POSTing to a single resource ? Should it return a 405 Method Not Allowed, as you shouldn't be allowed to POST to a single resource or should it return a 404 Not Found as described here ?
If, at the moment a request is received, a resource (regardless of the concept that it represents) does not support a particular method (POST), the correct response to return is 405
The 405 (Method Not Allowed) status code indicates that the method received in the request-line is known by the origin server but not supported by the target resource. The origin server MUST generate an Allow header field in a 405 response containing a list of the target resource's currently supported methods.
The HTTP Specification includes a method (OPTIONS) and response headers (Allow) that enable a client to interrogate a server to discover what methods are permitted. Adoption might be lacking, although I suppose CORS changes that.
Note: there are use cases where POST to a singular resource is a reasonable option (consider how you would define the protocol to star a responsitory in an api where HTML was your hypermedia format). In that case, you should choose the appropriate success code (200, 201, 204...), assuming things went well, of course.
If someone tries to POST to a specific item where it should have call PUT to update. In my opinion 404 should be correct return status code, it tells the client that the resource they are looking is unavailable, which means the URL they are hitting isn't correct.
405 method not allowed should be invoked when client is hitting the right URL with wrong method type. suppose you have /api/users/{id} with PUT, but client is using POST.

Status code to return on not found sub-resource

So let's say I have two resources, Wallet and User. The User and Wallet have a one-to-one relationship. In my REST API, I give the option to give the User a different Wallet, by ID. So a typical HTTP PUT request to move the user to a different wallet could look like this:
PUT /api/user/3 HTTP/1.1
Host: api.myuserandwalletwebsite.com
{
"wallet_id": 15
}
This will update the User to use the wallet with id=15. But, what if the PUT request contains a wallet_id that is not found in the database; what should the REST API then return? Just a simple 404?
Returning a 404 on a sub-resource not found feels weird to me, because the 404 would be misleading: you could think the 404 actually refers to the user not being found.
404 (Not Found) is definitely not the correct response code. The response code you want is 422 (Unprocessable Entity).
The 422 (Unprocessable Entity) status code means the server
understands the content type of the request entity (hence a
415(Unsupported Media Type) status code is inappropriate), and the
syntax of the request entity is correct (thus a 400 (Bad Request)
status code is inappropriate) but was unable to process the contained
instructions.
    -- RFC 4918
It is a well-understood and well-defined response code, and can be found in the Hypertext Transfer Protocol (HTTP) Status Code Registry maintained by IANA.
As a side note, you're not using HTTP PUT according to the spec. A PUT should update the entire contents of the resource in an idempotent manner. You should be using either PATCH or POST.
As an alternative, you might consider a joining resource, such as a /user-wallet endpoint. That may or may not make sense depending on the specifics of your API.
Like you already mentioned: I would also not use 404, because it would mean the user could not be found. As you want to update your User resource and this update fails due to invalid data (a reference to an invalid Wallet) I would rather use 400 Bad Request and add a meaningful message to an additional header field (e.g. X-Message: Wallet with ID 15 not found).
HTTP 422 Unprocessable Entity is also a good idea, but not covered in RFC2616. If this "extension" is no problem you can go with this one.
HTTP 405 is not correct here as this would mean the PUT method is generally not allowed on the users resource and that PUT would not be included when firing OPTIONS to the resource which is not the case.
In my application that using REST-API I trying to follow best-practises described here: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
And I know many programmers from GOOD Software development companies that also take care about this.
So as was described in best-practises in case of not found resources just simple use:
404 Not Found - When a non-existent resource is requested
That is first case - common best practises.
Second: thing behind best REST-API practisies is Your application logic:
I think You have some options based on Your app-logic :
404 Not Found - When a non-existent resource is requested because You requested non-existing wallet
405 Method Not Allowed - You cant put because wallet not found and it is required for update
422 Unprocessable Entity - Used for validation errors because we have validation in our app that check for incomming requests
So concrete status is only Your decision. Remember the option that You choose will propagate for rest of Your logic application so be consistent and consider the REST-API like GUI dedicated for other application

400 vs 422 response to POST that references an unknown entity

I'm trying to figure out what the correct status code to return on different scenarios with a "rest-like" API that I'm working on.
This example is borrowed from another question about syntax type issues in the body, but my question assumes valid syntax throughout.
Let's say I have an endpoint that allows POST'ing purchases in JSON format. It looks like this:
{
"account_number": 45645511,
"upc": "00490000486",
"price": 1.00,
"tax": 0.08
}
What is the appropriate status code if:
the account number does not exist
the account is closed or the
account identified is not the right kind of account
These are all firmly business layer issues that prevent "processing" from occuring, however, one scenario involves something that in a GET would be a 404.
Note that the account number is not in the URL, so is 404 misleading?
Let's take these one at a time. Each of these codes is a signal to your client that the server is functioning correctly, and that something must be changed in the request before it can be successfully carried out.
HTTP 400
The 400 (Bad Request) 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).
400 typically indicates a syntax error; as a user, I should look at the structure of the request before trying again.
HTTP 404
The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent. The 410 (Gone) status code SHOULD be used if the server knows, through some internally configurable mechanism, that an old resource is permanently unavailable and has no forwarding address. This status code is commonly used when the server does not wish to reveal exactly why the request has been refused, or when no other response is applicable.
404 is the standard code used when a web server can't match a url path to anything. As a client, I should look at the URL of the request before trying again.
HTTP 422
The 422 (Unprocessable Entity) status code means the server understands the content type of the request entity (hence a 415 (Unsupported Media Type) status code is inappropriate), and the syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions. For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.
422 is generally used for content violations. As a user, I should look at the content of my request before trying again.
Now in your case, account number is an identifying number, but is not included in the URL. A 404 would signal to your user that the URL is wrong, not the payload. Stated another way, suppose your url is:
http://www.myservice.net/endpoint
A 404 would indicate to me that no service exists at /endpoint, instead of no account number. No matter what content I submit, the server will not process my request. The fix I should make then would be to look for an error in the URL, instead of the data payload. So to me a 422 would point me in the right direction, unless you begin to include the account number in the URL.
Ultimately these are design preferences, just make sure you communicate them clearly to your users.
If you consider the accounts to be part of the state of the resource (though indirectly) then you might also consider 409 since that state is in conflict with the semantics of the request.
However, 422 is gaining popularity via Ruby on Rails and Dropwizard where it is used to indicate non-syntactic issues with the body. That growing tendency represents a strong signal to a developer using the API that they need to exclude syntax and focus on the body. Developer time is usually the single largest cost your customers will ever incur, so by directing the attention of their developers you will keep them happy.
So 409 is a possible answer, though rather novel, and 422 is the more conventional approach, although obviously RoR and DropWizard are both rather new so these conventions can be said to be changing fast!
I'd say 422 is adequate in your case, but 400 isn't bad if it's consistent with the rest of your API. It's a common convention to use 400 as an umbrella error code when there's something wrong on the client side, but either the error doesn't fit a particular error code, or you don't want to use too many of them.
A 404 is definitely wrong if there's something wrong with the POST payload.
Case 1 : Account number doesn't exist.
This is a standard case for 404.
Case 2 : Account is closed.
This has do with the logic if you keep the account details when you close it.
If you donot keep the account details when the account is closed, you can give 404.
If you keep the account details after it is closed, you must be marking it (like raising some flag) (or whatever logic you have). In this case, Status code 400 with a proper message of why it is failed and possibly remediation will do.
Case 3 : Account identified is not the right kind of account.
403, as the account is not authorised for completing any purchases makes sense to me. If there is no concept like authorised account, 400 with a explanatory message will do. But I would insist to go with 403 in this case.
Actually, in this case 404 sounds good to me.