HTTP Error Code while trying to change an immutable object? - rest

I have a quiz in which I can give an answer to a question over a restful API. The request will transmit the answer to the question over a PUT-Request to an URL like “/question/{id}/answer”. But each question can only be answered once. The answer can be queried over a get request but can never be changed again. What HTTP Error Code do I return when the client tries to change the immutable answer with a PUT request?
I tried this error codes:
405 Method Not Allowed: But in the first place a PUT is fine. But once the object is set a PUT is not allowed anymore. Is it OK if the list of allowed methods change over time?
409 Conflict: Would work, but the RfC says “his code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request.” And here the client would not be able to resolve the conflict.
400 Bad Request: It is in general a bad request but not “due to malformed syntax.”
So, is it a Server Error (5xx)? In case of a 500 Internal Server Error the RfC states that “The server encountered an unexpected condition”. But we expect the object to become immutable at some point.

Is it OK if the list of allowed methods change over time?
Yes.
Allow header field in a 405 response containing a list of the target resource's currently supported methods. -- RFC 7231
Note: currently supported methods....

Related

Should a REST API return a 404 when POSTing a non-existing ID?

As far as I understand it, in addition to returning a 404 Not Found for unknown endpoints, a REST API should also return a 404 in the following cases:
requesting a resource with an ID that does not exist in the path: route /users/{id} exists, but /users/123456 does not exist
requesting a resource with an ID that does not exist in the query parameters: route /search exists, but /search?user=123456 returns a 404 if the user does not exist (I asked a similar question a few years ago)
Now what about the use case where an endpoint accepts a JSON object with a number of fields, one of them being the ID of a user that does not exist:
POST /makeReservation HTTP/1.1
...
{
"userId": 123456,
...
}
Should this return a 404 as well, or is this considered a different kind of error (validation error?) in this case?
As far as I understand it
I'd say your current understanding is a little bit more complicated than it should be.
404 Not Found means:
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.
In case "target resource" is unclear, we can review the specification of the Request Line.
request-line = method SP request-target SP HTTP-version CRLF
The request-target identifies the target resource upon which to apply the request, as defined in Section 5.3.
In other words, 404 says "there is a problem with the spelling of the request-target".
Therefore, it is misleading to suggest that there is a problem with the request-target, when the actual problem is in the request body.
The error code you probably want for this case 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. For example, this error condition may occur if an XML
request body contains well-formed (i.e., syntactically correct), but
semantically erroneous, XML instructions.
IANA's HTTP Status Code Registry is a good place to look when you are sure that there should be a standardized code for your use case, but you are having trouble guessing which specification describes it.
it's part of WebDAV and I'm not sure how correct it is to use it for other applications?
TL;DR: it's correct to use it for other applications.
The HTTP specification defines the process by which new codes can be added to the status code registry, and that process has been followed for the WebDAV codes. So we can be confident that the meaning of 422 won't be replaced by some other semantic (for compatibility, status codes are retired -- see status code 306.)
The definition of 422 in the WebDAV specification is not WebDAV specific.
Furthermore, the behavior of clients that are not aware of the WebDAV specification is described in RFC 7231
a client MUST understand the class of any status code, as indicated by the first digit, and treat an unrecognized status code as being equivalent to the x00 status code of that class, with the exception that a recipient MUST NOT cache a response with an unrecognized status code.
You can also review appendix B of the WebDAV specification.
(As a side note, I think your concern is reasonable -- WebDAV methods are much harder to re-use outside of that context.)
Update 2022-07-12: the IANA registered reference for status code 422 is now RFC 9110 (HTTP Semantics). We no longer need be concerned when we use that status code outside of a WebDAV context.

HTTP status code for PATCH requests meaning "you are not allowed to make such request"

I am trying to implement some PATCH requests in our software(following https://www.rfc-editor.org/rfc/rfc7396). The resources have some fields which must not be modified, so I am thinking to return some error status code when such fields appear in HTTP JSON request body. 400 seems a bit too generic (I am using it for validation errors e.g. email format and the like). Perhaps there is some other status code used in such situations?
There's a code for that . . . 8-)
403 Forbidden
The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason
https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
Furthermore, 403 is suitable even if there are no credential problems.
This is explained in RFC7231 Section 6.5.3:
a request might be forbidden for reasons
unrelated to the credentials
RFC 7231 section 8.2 a status code registry, so that's the place to start.
This is clearly a problem with the request; something the client might be able to fix, so an entry from the 4xx class is appropriate.
405 Method Not Allowed is wrong for the case you describe -- a different merge patch document would be accepted by this resource, but not the one that is present.
403 Forbidden is wrong, as it communicates a problem related to credentials, but you are describing a problem with payload.
409 Conflict could be reasonable...
the request could not be completed due to a conflict with the current state of the target resource.
I don't see any reason that the conflict can't be in an immutable part of the "current state".
But I think your best bet 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. For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.
Another good resource to consider is the HTTP Patch specification. RFC 5789 enumerates a number of reasons that a patch might fail, and what code would be appropriate to use in each context. You can decide for yourself whether you think those distinctions are appropriate in your circumstances.
There may also be more specific errors like "Conflicting State" that could be signaled with this status code, but the more specific error would generally be more helpful.

Is it OK to put semantic information in the HTTP reason-phrase in a REST API?

For example, I might want to return the current sequence number of the resource with a 409 response to a HEAD request to a versioned resource, but I may not supply it in the response entity because HEAD doesn't allow any. Another example: suppose a POST request to a commit endpoint fails due to version conflict. I can respond with 409, but sometimes I may want to additionally inform the client that the transaction it was committing has exceeded the maximum retry count and further attempts will not be successful. I might return e.g. HTTP/1.1 409 Conflict/final instead of just HTTP/1.1 409 Conflict in this case. My question is, is this acceptable practice? HTTP 1.1 RFC does not supply a clear-cut answer to this question.
I know I can put such information in a X-... HTTP header, or include this information in the response entity in some manner (additional XML tag or JSON property etc.) Assume I can't or don't want to do so if I can help it.
The reason phrase is cute for debugging; but that's it. It's gone in HTTP/2, and may be lost by intermediaries and/or software libraries; don't rely on it being preserved.
The format of the HTTP response is
Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
As per the spec,Here Reason Phrase can be custom. You can add your version of the error message.Please check here http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html. It mentions that
The reason phrases listed here are only recommendations -- they MAY be replaced by local equivalents without affecting the protocol.

HTTP Status codes confusion

So, I am trying to display meaningful and accurate HTTP status codes and I'm getting confused even after going through the examples online. Here's my situation:
In the URL which accepts the query param:
#POST query
Sample URL: /putRecord?Name=A&Age=25&house=permanent
what status code do i return when one of the params is missing? (All 3 are mandatory) - from what I've read, I am guessing it is a 400: Bad request. But this seems too general. Is there a way for me to say that the query was malformed? Source:here
Assuming I validate the name for duplicates against the DB, if I get a duplicate, what status code do I return?
So, if there's a duplicate entry available already, I can't add the record. Do I display 304 (Not modified) or just the error code from 2?
Clarification: For 3, another possibility is when I can't actually commit to the DB and I rollback(possibly). What status code will it be now?
Thanks so much!
Ad 1. You can return, besides the code itself (400) also a short message with explanation. So, instead of returing "400 Bad Request" you could respond with "400 Query param name required" or something similar. This message is called "reason phrase" and is defined in 6.1 in RFC 2616. Or, if you need more flexibility, you could return document with the explanation.
Ad 2. I would consider using 422 Unprocessable entity. From the RFC 4918:
The 422 (Unprocessable Entity) status code means the server understands the content type of the request entity, 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.
Ad 3. I would return 422, but it really depends whether this situation is considered an error in your logic, or is it a regular, expected situation.
Edit: As #War10ck suggested in the comment, HTTP 409 (in place of HTTP 422) might make sense as well.
Note on handling duplicates: it seems (correct me if I'm wrong) that you consider new entity being a duplicate if it's name is already in the database. If so, that you could maybe consider using a HTTP PUT instead of HTTP POST?
You could define the following resource:
HTTP PUT /record/:name
So, "name" would be a part of the URI. Then, in case there is a second PUT to the same resource (same "name"), it'd be elegant to respond with 409/422.
If you're using different key for unique constraint, modify the URI appropriately.
As a rule of thumb, POST is for situations where you can have multiple instances of a given resource, i.e.
HTTP POST /log ;; Because we have many logs
And PUT for situations where each resource is unique:
HTTP PUT /person/:name (or /person/:tax-number if :name isn't unique)
Also, note that I've renamed your resource from "putRecord" to "record" - PUT is a HTTP method, no reason to have it in URI as well.

HTTP status code in REST API for using GET to query a “Not Ready Yet, Try Again Later” resource?

First of all, I've read some relevant posts:
Best HTTP status code in REST API for “Not Ready Yet, Try Again Later”? It is about GET an item
Is it wrong to return 202 “Accepted” in response to HTTP GET? It is about GET an item
HTTP Status Code for Resource not yet available It is about POST
HTTP status code for in progress? It is about GET but no clear answer.
but I still think I should raise my question and my thoughts here. What should be the HTTP status code in REST API for using GET to QUERY a “Not Ready Yet, Try Again Later” resource? For example, client tries to query all local news happen in future(!) by make an HTTP GET to this url: http://example.com/news?city=chicago&date=2099-12-31 so what shall the server reply?
These are the http status code I considered, their rfc definition and why I am not fully satisfied with:
3xx Redirection. Comment: Not an option because there is no other link to be redirected to.
503 Service Unavailable: The server is currently unable to handle the request due to a temporary overloading or maintenance of the server. The implication is that this is a temporary condition which will be alleviated after some delay. If known, the length of the delay MAY be indicated in a Retry-After header. Comment: The retry behavior is desired, but semantically the situation is not server's fault at all, so all 5xx look weird.
4xx Client Error. Comment: Looks promising. See below.
413 Request Entity Too Large: The server is refusing to process a request because the request entity is larger than the server is willing or able to process. ... If the condition is temporary, the server SHOULD include a Retry- After header field to indicate that it is temporary and after what time the client MAY try again. Comment: The retry behavior is desired, however the "Entity Too Large" part is somewhat misleading.
417 Expectation Failed: The expectation given in an Expect request-header field (see section 14.20) could not be met by this server. Comment: So it should be caused by an Expect request-header, not applicable to my case.
406 Not Acceptable: The resource ... not acceptable according to the accept headers sent in the request. Comment: so it is caused by the Accept request-header, not applicable to my case.
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. ... Conflicts are most likely to occur in response to a PUT request. Comment: This one is close. Although my case is not about PUT, and isn't actually caused by conflict.
404 Not Found: The server has not found anything matching the Request-URI. Comment: Technically, my url path (http://example.com/news) DOES exist, it is the parameters causing problems. In this case, returning an empty collection instead of a 404, is probably more appropriate.
403 Forbidden: The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. Comment: Generally this is supposed to be used in any restricted resource?
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. Comment: It is not true in my case. My server understands the request, its syntax is good, only the meaning is bad.
2xx Successful. Comment: If 4xx doesn't work, how about 2xx? See below.
200 OK. Comment: Fine. So what should I include in the response body? null or [] or {} or {"date": "2099-12-31", "content_list": null} or ... which one is more intuitive? On the other hand, I prefer a way to clearly differentiate the minor "future news" error from the more common "all query criteria are good, just no news this day" situation.
202 Accepted: The request has been accepted for processing, but the processing has not been completed. The request might or might not eventually be acted upon. Comment: Providing that we can use 202 in a GET request, it is acceptable. Then refer to the 200 comment.
204 No Content: The server has fulfilled the request but does not need to return an entity-body. Comment: Providing that we can use 204 in a GET request, it is acceptable. Just don't know whether this is better than 202 or 200.
More on 2xx: Comment: I assume all 2xx response will likely be cached somewhere. But in my case, if I return an empty body for "tomorrow's news", I don't want it to be cached. Ok, explicitly specify the "no cache" headers should help.
Your thoughts?
Use 404.
Your objection to it is based on a popular understanding of a URI as not including the querystring. "Because I have multiple URI's that map to the same handler," goes the logic, "my resource does in fact exist and is just being parameterized by querystring args."
This is incorrect. As the URI spec itself says in Section 3.3 (emphasis mine),
"The path component contains data, usually organized in hierarchical
form, that, along with data in the non-hierarchical query
component (Section 3.4), serves to identify a resource within the
scope of the URI's scheme and naming authority (if any)."
Resources are identified by URI's, and any change to any part of an absolute-URI identifies a separate resource. Tweet that to everyone you know once a day until they tell you to stop. Therefore a 404 is a perfect match: "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."
You are retrieving the news for that day, which is a valid day, there just isn't any news. A 200 response of an empty body, or a what ever makes sense based on the mediatype would seem the logical. This depends on the media type you have decided with the client.
404 would make more sense if the date format was wrong (you asked for the 45th day of November, or asked for a city that doesn't exist.)
As an aside the URL would be better in the format http://example.com/news/chicago/2099-12-31 since that is the specific resource you want to retrieve. This format would make things like 404s clearer as well.