Correct HTTP Status Code for requests that has something wrong with the process but not an exception - rest

The scenario is the client will request to delete an item in the table but the item is deleted already, not physically deleted so not a "NOT FOUND". Probably a 200 but it has not done the delete. Something like in between the 200 and a 500.
A return for a request for something to be done but it was not done successfully(so not a 200) but there is no exception(not a 500).

Status codes belong to the transfer documents over a network domain; you want to be thinking of them in terms of general purpose document transfer semantics, not anything specific to your implementation.
One of the interesting characteristics of unsafe idempotent methods is that they are, in a sense, declarative -- "make the resource be like this". If the resource is already in the desired state, you can return a success response to indicate that.
This is made explicit in RFC 7232, discussing the implications of If-Match headers:
An origin server MUST NOT perform the requested method if a received If-Match condition evaluates to false; instead, the origin server MUST respond with either a) the 412 (Precondition Failed) status code or b) one of the 2xx (Successful) status codes if the origin server has verified that a state change is being requested and the final state is already reflected in the current state of the target resource (i.e., the change requested by the user agent has already succeeded, but the user agent might not be aware of it, perhaps because the prior response was lost or a compatible change was made by some other user agent).
Fundamentally, HTTP doesn't constrain what servers do (implementation), but only what the messages mean (semantics). In the case of a No-Op, returning a message with a success code has perfectly satisfactory meaning, and in particular induces (in a standards compliant client) exactly the sorts of responses that we want.
Success codes can also be appropriate when an unsafe request changes a resource, but not in the expected way. Again, the server has authority over its own implementation, what we're largely interested in is what information is communicated to the client.
As an example, I submit a reimbursement request. What I expect is that my request goes to the "approved" state, but it might instead transition to "under review" if some business rule has kicked in. I still expect to receive a 2xx status code back, even though the server didn't do "what I wanted", because the message has been received and acted upon, and my previously cached copy of the resource involved is no longer valid.

If you are doing a request on a resource that doesn't exist, you can still just use 404 Not Found. Whether something is 'physically deleted' or not is irrelevant to the client.
If you know for a fact that it's deleted before and it's never coming back, 410 Gone is also appropriate

Related

How to handle PUT endpoint with immutable resource

A microservice I develop exposes a single endpoint, PUT /deployments/{uuid} . The endpoint is used to initiate a potentially expensive deployment operation, so we only ever want it to happen once, which is why we chose PUT + UUID over POST (for uniqueness). The deployment is immutable, so it can never be updated, so we currently raise an exception if the PUT is called more than once with the same uuid.
As a person who loves bikeshedding and therefore cares deeply about restfulness, this grinds my gears. PUT is supposed to be idempotent, so raising an exception after making the same request multiple times is an antipattern. However, we have a requirement to not allow sequential identical requests to generate new deployments, so the usual POST is out.
While the best solution is one that works, I'd like ours to be a little more elegant, if possible. I've posited a POST with the UUID in the payload, but my team seems to think that's worse than the current solution. I'm considering just returning a 200 OK from a PUT to the same UUID rather than a 201 CREATED, but I'm not sure if that has the same problem as non-idempotent-put in not semantically conveying the information I want.
Is there a "best solution" here? Or am I doomed to be "that guy" on my team if I pursue this further (joke's on you i'm already that guy).
tl;dr What is the correct RESTful API signature for a /deployments endpoint that is immutable, and required to not allow the same request to be processed twice?
Idempotent does not mean "2 identical requests should yield the same response". It means: "The server state after 2 identical requests should be the same as when only 1 is made".
A similar example, if you call DELETE on a resource and get a 204 No Content back, and call DELETE again and get a 404, this doesn't violate the idempotency requirement. After the second delete the resource is still removed, just like it was after the first.
So multiple identical idempotent requests are allowed to give different responses.
That said though, I think it might be nicer to the second identical request to also get a 2xx status back. It doesn't have to be the same as the first.
The use-case is if a client sent a HTTP request but got disconnected before it got a response. The client should retry and if the server detects the request is the same as the first, the server can just give the client a success response (but don't do anything).
This is generally a good idea, because if the client got an error back for the second request, it might be harder to know if the request failed because it succeeded earlier, or for other reasons.
That all being said though, there is also a way here to have your cake and eat it too.
A client could send the following header along with the PUT request:
If-None-Match: *
If the client omits the header, you can always return 424 Precondition Required.
If the resource does not yet exist, it's a success response. If the resource was created earlier, you can return 412 Precondition Failed.
Using this mechanism a client has a standard way to figure out that the request failed because a successful one was made earlier.
Based on the docs here, PUT is the best method to use. The response should be 201 when it triggers the deployment, and either 200 or 204 when nothing is changed. It shouldn't be POST because calling a POST endpoint twice should trigger the effect both times.

Status code for "resource will never be available in this case"

I have a REST API dealing with invoices. Now each invoice has a special "fee list" after it gets financed. Although not all are meant to be financed. I have an endpoint which provides information about this fee list for each invoice. So if an invoice has been financed, it returns 200, if invoice has not yet been financed (so the resource is not yet available but will be) I return 202 but what if invoice is not meant to be financed (resource is unavailable and never will be, in this case)?
I thought of using:
2xx - could not find any code that would match the situation
3xx - disagree with "client must take additional action to complete the request"
4xx - disagree with "situations in which the error seems to have been caused by the client"
5xx - disagree with "the server failed to fulfil a request"
Any ideas? Thanks!
I have an endpoint which provides information about this fee list for each invoice. So if an invoice has been financed, it returns 200, if invoice has not yet been financed (so the resource is not yet available but will be) I return 202 but what if invoice is not meant to be financed (resource is unavailable and never will be, in this case)?
An important thing to understand in REST, is that the metadata (status codes, headers) are describing resources (documents), not domain entities.
Sometimes, this idea is expressed "your resource model is not your domain model".
Your domain specific client is supposed to be looking at the payloads of the responses; the metadata describes the domain agnostic concerns of the hypermedia resource itself, so that generic components (browsers, caches, proxies, spiders) can contribute.
Another way of expressing the same idea: what we're really doing is sending messages back and forth. The message for the domain specific client belongs in the payload; so that's where you would communicate to the client what's going on with the invoice. The metadata is used to describe things like "how long should this particular message be cached?"
If I were designing your API, most of the responses would use 200 OK as the status code; with the occasional 404 Not Found when it appears that there may be a spelling mistake in the target URI.
(I probably wouldn't use 202 Accepted as you have described it, as the semantics mean something different -- 202 is much closer to "I understood your request, but its going to take me some time to get the document ready")
First of all, it's important to highlight that status codes are meant to indicate the result of the server's attempt to understand and satisfy the client request.
So, if resource is unavailable means that such resource doesn't exist (hence no representation can be found for such resource), then 404 is a quite reasonable choice:
The 404 (Not Found) status code indicates that the origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
From your question, I can understand that not meant to be financed doesn't mean that a representation doesn't exist for such resource. So, if the resource exists (and there's a representation for it), then a 200 seems to be just fine:
The 200 (OK) status code indicates that the request has succeeded.
According to https://www.rfc-editor.org/rfc/rfc7231#section-6.5.4 :
The 404 (Not Found) status code indicates that the origin server did
not find a current representation for the target resource or is not
willing to disclose that one exists. A 404 status code does not
indicate whether this lack of representation is temporary or
permanent; the 410 (Gone) status code is preferred over 404 if the
origin server knows [...] that
the condition is likely to be permanent.
And also:
The 410 (Gone) status code indicates that access to the target resource is no longer available at the origin server and that this condition is likely to be permanent.
So, if you have a resource that is something like /invoice/123/feelist and that resource will never be available, then the closest you can get is 410 because 404 has no indication as to whether the condition is permanent or not.

Cannot Delete Last Contact - What Http Status Code?

I'm currently building a Web API and have a specific scenario that I cannot determine which HTTP Status Code would be most appropriate to return.
The Scenario
I have a "client" resource which owns a collection of contact resources.
The invariant is that a client must always have at least one contact. Therefore, if a request is made to delete a contact and this contact is the last remaining contact for the given client, I need to return an appropriate HTTP response indicating that the request cannot be fulfilled as you "Cannot Delete the last contact".
My feeling is this should fall under the category of "4xx Client Error's"
I've considered the following Status Codes:
400 Bad Request - I've ruled this out as it's specifically regarding malformed request's in which the server is unable to understand.
405 Method Not Allowed - at first this seems suitable, but I think 405 indicates that this method should never be allowed, however the above scenario is only transient. Thoughts?
409 Conflict - I've been leaning towards this, however the common example given for this code is generally a concurrency exception/edit conflict.
Does anyone have any guidance as to how I should respond in this scenario?
The key is to look at the expectations on the client and caches when a particular status code is used.
Here's some chunks of RFC2616 that are useful to look at:
10.4.1. 400 Bad Request
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.
This indicates that the request itself is completely wrong - either syntactically or by the protocol. Your specific case is really an application protocol error so this may indeed be appropriate.
10.4.6. 405 Method Not Allowed
The method specified in the Request-Line is not allowed for the resource identified by the Request-URI. The response MUST include an Allow header containing a list of valid methods for the requested resource.
This is a transient status code. If the DELETE refers specifically to the contact resources itself (e.g., DELETE /contacts/D9DF5176-EEE4-4C70-8DA7-BA57B82027A8) then this is probably the most appropriate status code. However, if the DELETE is on a different resource or a resource with a query (e.g., DELETE /contacts?index=12), then I would not return a 405. Then again, I usually steer clear of using DELETE with anything resembling a query.
10.4.10. 409 Conflict
The request could not be completed due to a conflict with the current state of the resource. This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request. The response body SHOULD include enough information for the user to recognize the source of the conflict. Ideally, the response entity would include enough information for the user or user agent to fix the problem; however, that might not be possible and is not required.
This seems like the most appropriate status at first look. I would probably prefer a 400 in your case. A 409 would clearly indicate that there is a conflict with the resource but there really isn't anything that the requestor can do that could change the outcome short of completely altering the resource (i.e., add a contact first). Most of the 409 responses were optimistic concurrency failures such as trying to modify a resource that was modified since it was retrieved. For example, look at the concurrency failures returned by AtomServer built over Apache Adbera.
So with all of that. I would probably use something like 400 Cannot Delete Last Contact as the response line. Remember that you are allowed to change the phrase associated with the status code. This is a really good time to do such a thing.

Status code when deleting a resource using HTTP DELETE for the second time

Given that the DELETE verb in HTTP is idempotent, when I issue the following request, what should happen the second (or third, or fourth, etc...) time I make it?
DELETE /person/123
The first time, the resource is deleted and I return a 204 (successful, no content). Should I return a 204 on subsequent calls or a 404 (not found)?
As HTTP requests in a stateless system should be independent, the results of one request should not be dependent on a previous request. Consider what should happen if two users did a DELETE on the same resource simultaneously. It makes sense for the second request to get a 404. The same should be true if one user makes two requests.
I am guessing that having DELETE return two different responses does not feel idempotent to you. I find it useful to think of idempotent requests as leaving the system in the same state, not necessarily having the same response. So regardless of whether you DELETE an existing resource, or attempt to DELETE a resource that does not exist, the server resource state is the same.
I agree with what the current chosen answer has said, that the 2nd (and 3rd, 4th, ...) DELETE should get a 404. And, I noticed that answer has 143 up votes but also has an opposite comment which has 54 up votes, so the community is divided into 2 camps in roughly 3:1 ratio. Here comes more information to settle this long time debate.
First of all, let's NOT start with what "I" think, what "you" think, or what yet another book author thinks. Let's start with the HTTP specs i.e. RFC 7231.
RFC 7231, section 4.3.5 DELETE happened to only mention a successful response should be 2xx, but it did not call out what a subsequent DELETE would get. So let's dig deeper.
RFC 7231, section 6.5.4 404 Not Found says 404 response is for a resource does not exist. Since no specific http method (in particular, not DELETE) being called out to be treated otherwise, we can intuitively get an impression (and rightfully so), that my request DELETE /some/resource/which/does/not/exist should result in a 404. Then, DELETE /some/resource/which/happened/to/be/removed/by/someone/else/five/days/ago might as well also return a 404. Then, why should DELETE /some/resource/i/deleted/five/seconds/ago be any different?
"But how about idempotency?!", I can hear you are screaming that. Hang on, we are about to get into that.
Historically, RFC 2616, published at 1999, was the most-referenced HTTP 1.1 specs. Unfortunately its description on idempotency was vague, that leaves room for all these debates. But that specs has been superseded by RFC 7231. Quoted from RFC 7231, section 4.2.2 Idempotent Methods, emphasis mine:
A request method is considered "idempotent" if the intended EFFECT ON
THE SERVER of multiple identical requests with that method is the
same as the effect for a single such request. Of the request methods
defined by this specification, PUT, DELETE, and safe request methods
are idempotent.
So, it is written in the specs, idempotency is all about the effect on the server. The first DELETE returning a 204 and then subsequent DELETE returning 404, such different status code does NOT make the DELETE non-idempotent. Using this argument to justify a subsequent 204 return, is simply irrelevant.
OK so it is not about idempotency. But then a follow-up question may be, what if we still choose to use 204 in subsequent DELETE? Is it OK?
Good question. The motivation is understandable: to allow the client to still reach its intended outcome, without worrying about error handling. I would say, returning 204 in subsequent DELETE, is a largely harmless server-side "white lie", which the client-side won't immediately tell a difference. That's why there are ~25% people doing that in the wild and it seemingly still works. Just keep in mind that, such lie can be considered semantically weird, because GET /non-exist returns 404 but DELETE /non-exist gives 204, at that point the client would figure out your service does not fully comply with section 6.5.4 404 Not Found.
But I want to point out that, the intended way hinted by RFC 7231, i.e. returning 404 on subsequent DELETE, shouldn't be an issue in the first place. 3x more developers chose to do that, and did you ever hear a major incident or complain caused by a client not being able to handle 404? Presumably, nope, and that is because, any decent client which implements HTTP DELETE (or any HTTP method, for that matter), would not blindly assume the result would always be successful 2xx. And then, once the developer starts to consider the error handling, 404 Not Found would be one of the first errors that comes into mind. At that point, he/she would probably draw a conclusion that, it is semantically safe for an HTTP DELETE operation to ignore a 404 error. And they did so.
Problem solved.
The RESTful web services cookbook is a great resource for this. By chance, its google preview show the page about DELETE (page 11):
The DELETE method is idempotent. This
implies that the server must return
response code 200 (OK) even if the
server deleted the resource in a
previous request. But in practice,
implementing DELETE as an idempotent
operation requires the server to keep
track of all deleted resources.
Otherwise, it can return a 404 (Not
Found).
First DELETE: 200 or 204.
Subsequent DELETEs: 200 or 204.
Rationale: DELETE should be idempotent. If you return 404 on a second DELETE, your response is changing from a success code to an error code. The client program may take incorrect actions based on the assumption the DELETE failed.
Example:
Suppose your DELETE operation is part of a multi-step operation (or a "saga") executed by the client program.
The client program may be a mobile app performing a bank transaction, for example.
Let's say the client program has an automatic retry for a DELETE operation (it makes sense, because DELETE is supposed to be idempotent).
Let's say the first DELETE was executed successfully, but the 200 response got lost on its way to the client program.
The client program will retry the DELETE.
If the second attempt returns 404, the client program may cancel the overall operation because of this error code.
But because the first DELETE executed successfully on the server, the system may be left at an inconsistent state.
If the second attempt returns 200 or 204, the client program will proceed as expected.
Just to illustrate the use of this approach, the HTTP API style guide for PayPal has the following guideline:
DELETE: This method SHOULD return status code 204 as there is no need to return any content in most cases as the request is to delete a resource and it was successfully deleted.
As the DELETE method MUST be idempotent as well, it SHOULD still return 204, even if the resource was already deleted. Usually the API consumer does not care if the resource was deleted as part of this operation, or before. This is also the reason why 204 instead of 404 should be returned.

What's the correct way to view idempotency in terms of HTTP DELETE?

I have spent a lot of time recently reading the HTTP 1.1 specification and relating it to REST. I have found that there are two interpretations of the HTTP DELETE method in regards to its "idempotency" and safety. Here are the two camps:
If you delete a resource with HTTP DELETE, and it succeeds (200 OK), and then you try to delete that resource N number of times, you should get back a success message (200 OK) for each and every one of those delete calls. This is its "idempotencyness".
If you delete a resource with HTTP DELETE, and it succeeds (200 OK), and then you try to delete that resource again, you should get back an error message (410 Gone) because the resource was deleted.
The specification says DELETE is idempotent, sure, but it also says that sequences of idempotent events can still produce side effects. I really feel like the second camp is correct, and the first is misleading. What "safety" have we introduced by allowing clients to think they were the cause for deleting a resource previously deleted?
There are a LOT of people in the first camp, including several authors on the subject, so I wanted to check if there was some compelling reason other than emotions that lead people into the first camp.
Being idempotent does not mean that a request is not allowed to have side-effects (that's what the 'safe' property describes). It just mean that issuing the same request multiple times will not result in different or additional side-effects.
In my opinion, the subsequent DELETE request should return an error - it's still idempotent because the state of the server is that same as if only one DELETE request were made. Then again returning the 200 OK status should be OK as well - I don't think being idempotent requires the returning of an error code for the subsequent DELETE requests - it's just that returning the error status seems to make more sense to me.
#MichaelBurr is correct about idempotency and side-effects.
My opinion is that there are 2 states involved in a given REST request, the client's state and the server's state. REST is all about transferring these states between the server and the client, such that the client's state maps to a subset of the server's state, in other words, the subset stays consistent with the server. Because of that idempotency should mean that subsequent idempotent requests will not result in either state being different than it would be from only making the request once. With the first DELETE you would imagine that the server deletes the resource and lets the client know it can delete the resource as well (as the resource "doesn't exist anymore"). Now both states should be identical to before with minus the item that was deleted. For the client to do anything different when it tries to delete the item after it has already been deleted, then the state that is transfered from the server to the client must contain different information. The server can do things slightly differently with the information that the resource was already deleted, but once it responds with something different idempotency of the methods is essentially broken.
For idempotent function:
delete(client_state) -> client_state - {item}
delete(delete(client_state)) -> client_state - {item}
delete(client_state) = delete(delete(client_state))
The best way to guarantee this idempotency is if the server's response is identical, that means the only way for the client's state to break the idempotency is for there to be non-determinacy or side effects in the client's handling of the response (which probably points to an incorrect implementation of handling the response).
If there is an agreement between the client and server that the status codes exist outside of the representation of the state being transferred (REST), then it is possible to inform the client that the item "doesn't exists anymore" (as it would in the first request) with the extra comment that it had previously been deleted. What the client does with this information is unclear, but it shouldn't effect the resulting client state. But then the status code can't be used to communicate state, or rather if it does also communicate state in other situations (like maybe "you don't have permission to delete this item" or "item was not deleted"), then there's some introduced ambiguity or confusion. So, you at least need a pretty good reason for introducing more confusion into the communication if you want to say that DELETE is idempotent and still have the server's response depend on previous DELETE requests that are identical.
HTTP requests involve remove methods, so the function might resemble
delete(client_state) = send_delete(client_state) -> receive_delete(client_state)
-> respond_to_delete(informative_state)
-> handle_response(informative_state)
-> client_state - {item}
Wikipedia defines Idempotence as an operation that:
can be applied multiple times without changing the result beyond the initial application.
Notice that they talk about the result of the operation. To me, this includes both the server state and the response code.
The HTTP specification is a bit more vague on the matter. It defines it specifies that HTTP methods are Idempotent:
if the intended effect of multiple identical requests is the same as for a single request.
If you interpret effect as result in the Wikipedia definition then they mean the same. In any case, I question the practical benefit of telling clients that the resource as already been deleted.
Final point: Idempotence is defined in terms of a single client. Once you start introducing concurrent requests by other clients, all bets are off. You are supposed to use conditional-update headers (such as If-Match-ETag) to deal with such cases.
To reiterate: you should return the same return code, whether the resource just got deleted, was deleted by a previous request, or never existed at all.