This is kind of an OCD thing to worry about, so feel free to close, especially since changing this could have back-compat concerns.
restify.InvalidArgumentError and restify.MissingParameterError map to status code 409, which is defined as
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.
Conflicts are most likely to occur in response to a PUT request. For example, if versioning were being used and the entity being PUT included changes to a resource which conflict with those made by an earlier (third-party) request, the server might use the 409 response to indicate that it can't complete the request. In this case, the response entity would likely contain a list of the differences between the two versions in a format defined by the response Content-Type.
(emphasis added). This doesn't seem like a good match for "invalid argument" or "missing parameter". Indeed 409 usually seems to be used in REST APIs for the PUT conflict scenario described, more specifically with the ETag as the version.
Rather, I'd think 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 for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.
And if not that, 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.
Notably restify.InvalidContentError already uses 400, and seems to be in the same class as InvalidArgument and MissingParameter.
Thoughts? Again, this is a pretty minor detail. But if you agree, I'd happily submit a pull request.
Hey Dominic,
No it's not on OCD - so...the reality is there's no "real official"
spec on which HTTP codes to map to REST requests. 400 I prefer to
almost never use unless it's _actually_ an invalid request, as bad
request has semantics to the client that the actual HTTP request was
incorrect, not the API request that was tunneled on top. For better
or worse most things I've seen throw 409 back as the HTTP code when
there was an invalid API request (i.e., HTTP was ok, but the API was
invalid due to _something_ that the client could redrive).
The etag bit is pretty much always going to be throwing 412's (i.e.,
the user sent an if-match with etag), so that's not really the case
that throws 409s.
403 and 401 have pretty strong meaning that I wouldn't want to overload.
To some extent there's no real "right answer" here; the reality is
REST apis that are RPC (i.e., not content-based) ideally need some new
mapping of 4xx codes to correctly convey this without resorting to
tunneling codes back in the response body.
I did try to ensure that you can easily define your own RestErrors so
if you don't like what restify does, you don't have to use them. The
HttpErrors obviously are a 1:1 mapping to the possible 4xx status
codes, so you should be able to repeat the same pattern for your own
errors by just extending RestError the way restify does.
I know that's not what you necessarily wanted to hear :\
m
On Wed, Apr 11, 2012 at 11:35 AM, Domenic Denicola
[email protected]
wrote:
This is kind of an OCD thing to worry about, so feel free to close, especially since changing this could have back-compat concerns.
restify.InvalidArgumentErrorandrestify.MissingParameterErrormap to status code 409, which is defined asThe 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.
Conflicts are most likely to occur in response to a PUT request. For example, if versioning were being used and the entity being PUT included changes to a resource which conflict with those made by an earlier (third-party) request, the server might use the 409 response to indicate that it can't complete the request. In this case, the response entity would likely contain a list of the differences between the two versions in a format defined by the response Content-Type.
(emphasis added). This doesn't seem like a good match for "invalid argument" or "missing parameter". Indeed 409 usually seems to be used in REST APIs for the PUT conflict scenario described, more specifically with the ETag as the version.
Rather, I'd think 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 for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.
And if not that, 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.
Notably
restify.InvalidContentErroralready uses 400, and seems to be in the same class as InvalidArgument andMissingParameter.
Thoughts? Again, this is a pretty minor detail. But if you agree, I'd happily submit a pull request.
Reply to this email directly or view it on GitHub:
https://github.com/mcavage/node-restify/issues/118
No worries! You've obviously thought about this quite a bit, which is enough for me.
I was indeed confused as to 412 vs. 409 for the etag case. And it sounds like you have more experience with what people are doing out there that justifies 409 over 403, whereas I was just trying to read the spec directly, which is always tricky since it's quite vague and as you say there's no clear right answer.
I think I'll give 409 a shot, then, and if, after living with it for a month or two, it still feels off, then maybe I'll derive a custom RestError or use the HttpError instance. As you say, that's pretty easy.
I just came across this issue for the same reason it was filed鈥攂ecause 409 seems strange.
How about 422? I've heard that recommended a bit: https://tools.ietf.org/html/rfc4918#page-78
422 -- +1... exactly what a conflict is for 409 seems unclear, but whatever it means, it should be possible to have an invalid argument without a conflict.
Most helpful comment
I just came across this issue for the same reason it was filed鈥攂ecause 409 seems strange.
How about 422? I've heard that recommended a bit: https://tools.ietf.org/html/rfc4918#page-78