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.

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.
Very special thanks to all Twitter people participating to the #choosehttpstatuscode polls and discussions

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.

Twitter poll results

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.

By continuing to use this web site you agree with the API Handyman website privacy policy (effective date , June 28, 2020).