Dilemma between 2xx and 4xx status codes in api rest - rest

I think this problem is not trivial, so I would like to express it in detail
Domain:
I have an endpoint (api rest) that receives a date and time of an appointment that I want to block (which will later be reserved). The operation is simple, when receiving the date and time, it is blocked so that another client can not book an appointment on the same day and time, while the one that blocks the appointment, completes the contact information.
So far, very simple. The problem begins when two different users select the same date and time in their browser and two requests are triggered simultaneously. As we already know, you can not block an appointment on the same day and time twice, so the application will fail (although this failure is properly controlled).
In short, two users try to block an appointment on the same date and time, and only the request that is processed first will succeed.
For the user who managed to block the appointment, the answer is clear: 200 OK status. The question is, which state code http corresponds to return to the second user?
Comment:
Very recently at work I have run into this dilemma, and I have argued strongly with a co-worker about it. Since then, I began to research hard and consult with several people with years of experience in the subject to be able to reach a conclusion.
2xx: Half of the people answered that the state code should be a 2xx. Why? first of all, because the request is well formulated (mainly the parameters, are written correctly) so it would not correspond to a client error (4xx) and on the other hand, it is not an unexpected error of the server (500), since it is duly controlled by the business logic itself. Since the query was done properly, it should send a 2xx status (more precisely a 200) indicating that the request was successful, with a message on the body, indicating the "status" of the action (the appointment could not be blocked) .
4xx: My position (and also that of the other 50% of those consulted) is that, as can be seen, the request fails because the desired action can not be completed. It does not seem logical at all, that a 200 OK is returned (indicating that everything went well) and a message describing the error or condition that occurred (in a way, it would be contradicting me). As an error occurred, there are only 2 possible guilty: the client and the server. In this case, it seems to me that the server is not, because it does not fail unexpectedly, but that business rule is well contemplated, and intentionally fails (so it would not be a 5xx). Everything seems to fit in that it is a client error, perhaps a semantic error, when trying to perform the same operation twice on the same resource. Therefore, my opinion is that an error 400 would adjust to the situation, and perhaps if we want to be a little more specific, a 409, indicating that we tried to modify concurrently a resource that does not allow this action.
What should be the appropriate option for this case?
Thanks!

Let us look at what the Wikipedia and MDN has to offer on this:
2xx (Successful): The request was successfully received, understood, and accepted
4xx (Client Error): The request contains bad syntax or cannot be fulfilled
(source: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)
In the case of an appointment conflict, the request of the second user is received and understood but can not be accepted so it would seem to be wrong to return a 2xx for such a case.
A situation qualifies for a 4xx either when the request contains a bad syntax (which is not the case here as the request is well-formed) or when the request cannot be fulfilled (which seems to be the case here which you want to communicate back to the client).
A suggestion can be to go ahead with 422 for such kind of errors which are specific to a business use case (such as an appointment scheduler for your case)
As per MDN:
The HyperText Transfer Protocol (HTTP) 422 Unprocessable Entity response status code indicates that the server understands the content type of the request entity, and the syntax of the request entity is correct, but it was unable to process the contained instructions.
(source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/422)
Also since booking an appointment would create a resource in the back-end (i.e. a valid appointment id with the details of visitor, time, etc.), I would prefer to send back 201 (Created) status code for the success case as you are executing the task in a synchronous manner. In my opinion, 200 (OK) status code is more suitable for situations when the resource would be asynchronously created and may not immediately be available when the server responses back to the client. In such cases we generally provide a GET request link from where the client can fetch the requested resource in future.

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.

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

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

REST response code for accessing a corrupt/invalid resource

What's the best HTTP status code to use in response to an HTTP GET for a resource that's corrupt or semantically invalid?
E.g., consider a request to GET /person/1234 where data for person ID 1234 exists on the server but violates some business rule, so the server refuses to use it.
404 doesn't apply (because the data actually exists).
4xx in general seems not ideal (because the problem is on the server end, not under the client's control).
503 seems to apply to the service as a whole, not a particular resource.
500 certainly fits, but it's very vague in actually telling the client what might be wrong.
Any suggestions?
After reading the comments and the linked resources, it looks like #RemyLebeau's approach is best:
I think 500 is the only official response code that fits this situation. And there is nothing stopping you from including a response body that describes the reason for the failure.
according to iana.org:
4xx: Client Error - The request contains bad syntax or cannot be fulfilled
5xx: Server Error - The server failed to fulfill an apparently valid request
I think none of the 4xx status code should be valid as a response to an internal server error or migration or ... where client has no responsibilities or where user's inputs are expected to be rechecked. unless user's pre-filled data are involved like maybe user's package is not allowing him to access that data after a pre-determinate and known date, in such specific case It may be valid a 403 Forbidden as #Bari did suggest.
I'm not an expert but I think when the rejection or the decision of considering endpoint data as corrupt or invalid is made by server, then it will depends on what should be done next. I see 3 possible cases:
1. It is expected that somehow this is going to be fixed and client
should be invited to request it back but at some future moment ==> 503 (Service Unavailable):
503 (Service Unavailable)
status code indicates that the server
is currently unable to handle the request due to a temporary overload
or scheduled maintenance, which will likely be alleviated after some
delay. The server MAY send a Retry-After header field
(Section 7.1.3) to suggest an appropriate amount of time for the
client to wait before retrying the request.
2. Something is wrong, it is not client responsibility but there is an alternative way to access data, maybe following a specific process or sending further details ==> 510 Not Extended
2. Server cannot fulfill the request but there is an alternative way that requires it to include further details. Example: when requested data is corrupt, server error response may include a list of older (or unsaved, unversioned) versions of it and expect client to be more specific about which version to select so it could be fetched instead of the corrupted one ==> 510 Not Extended
510 Not Extended
The policy for accessing the resource has not been met in the
request. The server should send back all the information necessary
for the client to issue an extended request. It is outside the scope
of this specification to specify how the extensions inform the
client.
If the 510 response contains information about extensions that were
not present in the initial request then the client MAY repeat the
request if it has reason to believe it can fulfill the extension
policy by modifying the request according to the information provided
in the 510 response. Otherwise the client MAY present any entity
included in the 510 response to the user, since that entity may
include relevant diagnostic information.
case 2 was updated to include an example as IMHO it may fit in such case. but again I'm not any expert and I may be
wrong about it
3. No alternative ways, nothing to be expected or none of the other cases ==> 500 should be good
500 (Internal Server Error)
status code indicates that the server
encountered an unexpected condition that prevented it from fulfilling
the request.

What status code should I return when part of a bulk update fails?

Let's say I'm a server responding to a request to do a bulk create of some entity. Let's say that I've also decided to make it so that if one instance of the entity can't be created, due to a server error or user error, I will still create the other entity instances. In this scenario what should I return? A 201 because I created most of the entities in the request? Or A 4xx/5xx since there was an error while creating one of the entities?
If you return a 4xx code it implies that the entire request has failed, and the server-state has not changed.
If the intent of the request is to do 'one or more things and some may fail', then a partial application is still a success, so that puts in the 2XX range.
206 is not a good idea. This is specifically for requests that use Range, which is not the case here.
207 could be used. You'll probably want to define a custom format instead of the default XML-based on. My vote would probably just go to 200.
Also, consider just doing many requests. Requests are cheap, why lump them together? Now each request can have their own beautiful, accurate status code.
In that case you could return a multi-status (207) response where you acknowledge the result for each batch entry. That way the client would have a complete awareness of the results. However, that type of HTTP status involves more complex processing on the client-side.
I think 201 is not a good choice because it says "Accepted" which mean everything is alright. But not in your case. Maybe 206 is a good idea which means "Partial Content" according to Wiki "The server is delivering only part of the resource..."

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.