Choosing HTTP status codes Series - Part 1
This is not the HTTP method you're looking for, HTTP status code 404 vs 405 vs 501
By Arnaud Lauret, April 21, 2021
When designing APIs, choosing HTTP status codes is not always that obvious and prone to errors, I hope this post series will help you to avoid common mistakes and choose an adapted one according to the context.
This first post answers the following question: given that a GET /resources/123
request returns a 200 OK
, what should be the response to DELETE /resources/123
if DELETE
method is not implemented? 404 Not Found
, 405 Method Not Allowed
or 501 Not Implemented
?
Choosing HTTP status codes Series
When designing APIs, choosing HTTP status codes is not always that obvious and prone to errors, I hope this post series will help you to avoid common mistakes and choose an adapted one according to the context.<div class="alert alert-info"> I never remember in which RFCs HTTP status codes are defined. To get a quick access to their documentation, I use Erik Wilde’s Web Concepts. </div>Very special thanks to all Twitter people participating to the #choosehttpstatuscode polls and discussions
- 1 - This is not the HTTP method you're looking for, HTTP status code 404 vs 405 vs 501
- 2 - Hands off that resource, HTTP status code 401 vs 403 vs 404
- 3 - Move along, no resource to see here (truly), HTTP status code 204 vs 403 vs 404 vs 410
- 4 - Empty list, HTTP status code 200 vs 204 vs 404
The context
In my Batch (Github) API calls with CSV and Postman runner and visualizer post, I used the Github REST API and discovered it was impossible to delete an issue on a repository with a DELETE /{user}/{repository}/issues/{issueId}
request simply because it was not implemented.
Unfortunately, the Github API warned me with a quite awkward 404 Not Found
though a GET
on the very same issue returned a 200 OK
that tells “this issue exists”.
That’s quite a contradiction.
According to a Twitter poll I made, a few voters (10%) agreed with Github REST API’s 404 Not Found
response, most people (56%) would use a 405 Method Not Allowed
, but a significant amount (34%) would use 501 Not Implemented
.
Let’s see which HTTP status code(s) can be used when a resource actually exists but the method provided in the request is not available.
Use 405 Method Not Allowed when method isn’t defined in contract
The 405 (Method Not Allowed) status code indicates that the method received in the request-line is known by the origin server but not supported by the target resource.
A 405
is a 4xx
class status code, which means it’s client’s fault.
Receiving such a response means the client sent to the origin server a request with a method that is not allowed/supported by the target resource.
Let’s rephrase that definition in the context of an API:
a consumer will get a 405 Method Not Allowed
response when sending a request with a method which is not explicitly mentioned in in the contract or documentation on the target resource.
For instance, that means if the API’s contract or documentation states the only method supported by a resource /resource
is GET
, a consumer sending a request on this resource using any other method, like DELETE /resource
for instance, will get a 405 Method Not Allowed
response.
Therefore, the 405
status code is the one I would have expected from the Github REST API when I tried to delete an issue.
Indeed, the API’s documentation describing the API’s contract of the issue resource (/{user}/{repository}/issues/{issueId}
) only mentions GET
and I sent DELETE
.
It’s clearly my fault, though it’s quite surprising to NOT be able to delete an issue (but that’s another story).
A 405 Method Not Allowed
is the right choice when the method is not defined in contract, but sending a “wrong” method is not always consumer’s fault, that’s where a 501 Not Implemented
could be interesting.
Use 501 Not Implemented when partially implementing a “standard”
The 501 (Not Implemented) status code indicates that the server does not support the functionality required to fulfill the request. This is the appropriate response when the server does not recognize the request method and is not capable of supporting it for any resource.
A 5xx
class error means the server is at fault.
A 501 Not Implemented
basically says “we’re deeply sorry but METHOD
has not been implemented on this resource and maybe has not been implemented at all on any resource”.
Sending a TOTALLY-UNKNOWN-METHOD /whatever-resource
could result in getting a 501
if the method does not match any generally known one, but in that case I would prefer to return a 405 Method Not Allowed
as it’s not the server’s fault if the consumer really sent a bullshit method in its request and must send an acceptable one.
But, imagine you are implementing a “more or less standard” interface contract. It could be because you work in a regulated industry like banking or an highly inter-connected one like travel or logistics. It could be because you want to implement a protocol such as WebDAV, which is a extended version of HTTP adding new methods. It could also be simply because inside your company several components have to share a common interface in order to facilitate communication.
Imagine now that standard contract you need to implement says consumer can use GET
and PUT
on /resource
but you only implement GET
in your version 1 for whatever reasonable reason.
In that case, returning a 501 Not Implemented
would be the perfect answer as the “standard” contract says that PUT /whatever-resource
is possible but it has not been implemented by the actual provider.
If a 501 Not Implemented
is a very good answer in such a context of partially implementing a “more or less standard” API, returning a 404 Not Found
is totally out of question in any HTTP method related error.
Never use 404 Not Found when receiving wrong or unknown method
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.
The Github REST API responded with a 404 Not Found
to my DELETE /issue-resource-path
request.
According to RFC 7231, that tells the issue identified by the path doesn’t exist (A) or Github is not willing to disclose that issue actually exists (B).
Unfortunately, both options were contradicted by the GET /issue-resource-path
returning a 200 OK
.
Indeed, getting this 200
tells the issue actually exists (Not A) and Github is willing to disclose it exists (Not B).
And even if for any reason I was actually not able to see this issue (we’ll talk about that in a later post) and so get a 404
on my GET
, I still would prefer to get a 405
on my DELETE
, that way I could have quickly know that whatever the issue I want to delete, I will never be able to delete it as it’s not possible according to the API’s contract.