Here are a couple gotchas I've seen more than once. Other opinions welcome.
Gotcha: Using 401 for 403 and vice versa
401 means that the client is NOT authenticated, and in some client libraries and browsers, this could trigger an authentication request. The server is required in HTTP to send the authentication challenge header. If the client is authenticated but doesn't have the right permissions, use 403 instead. Or if the client is unauthenticated but it doesn't matter, because no authentication would make the request succeed, 403 is also valid.
Gotcha: Using specific errors as general errors
There are three errors whose English titles make them seem broadly useful: 406 "Not Acceptable", 412 "Precondition Failed", and 417 "Expectation Failed". If your API has conditions that need to be met before other parts of the API can be used, it seems natural to use 412, right? The problem is these three all are tied to specific HTTP features, and are almost never appropriate to the standard kind of HTTP API.
- "Not Acceptable" is tied to the Accept header. Only if the request failed because of the client's Accept header choice, might this be the right error to use.
- "Precondition Failed" refers to precondition headers which include If, If-Match, If-None-Match, and If-Modified-Since. Use only if the request failed because of one of these precondition sent by the client.
- "Expectation Failed" is the same and refers to the Expect header.
In addition, I've collected a bunch of useful habits around error response bodies.
Tip: Use a response body on certain error responses.
It's perfectly legitimate to put a JSON body on a 4xx or 5xx response. The specification recommends it for some responses such as 409, where the error code indicates that the state of the resource makes the request fail, and it would sure help the client to know what the state of the resource is.
Tip: Include human-readable text
Boy does this help client developers.
Tip: Include machine-parsable detail codes
For example, if the API returns a number of 403 errors of different types, or 409 errors with different meanings, the client can handle those cases differently before even consulting the user. In the following example, the client could use the "uploadInProgress" key to know to automatically try again in 10 seconds if that's how the timeToWait was defined in the API documentation.
409 Conflict
Content-Type: application/JSON
Content-Length: xxx
{ "error": {
"text": "This object cannot be updated because an upload is currently being processed. Try again in a few seconds.",
"errorCode": "uploadInProgress",
"timeToWait": 10
}
}
Combining tip 2 and 3 produces a JSON response that has an envelope element "error" that can be extended to include more things, and extensibility is definitely good here.
No comments:
Post a Comment