41

Over the years, I have seen quite a few questions on this site along the lines of "can I invent my own HTTP response codes"? Generally asked by those who are developing both the server and client. The responses tend to go towards sticking with standard codes.

If I stick with standard HTTP status code numbers, is there any technical reason not to use custom text in order to differentiate between, let's say, multiple 501 responses?

To reiterate, no client except mine will ever see these values, which are returned by AJAX in repose to authenticated requests.

  • 10
    No I don't see any technical reasons why not. But I'd probably prefer such to lift it to a higher protocol level than transport from an architectural POV. I.e, not using 501 at all. – πάντα ῥεῖ Jan 25 '20 at 10:03
  • 25
    Any chance of proxies/firewalls in between? Could be an issue if you use "non-standard" stuff. – Mat Jan 25 '20 at 10:55
  • @πάνταῥεῖ can you clarify that? What do you mean by "`a higher protocol level`", with regard to AJAX? Thanks – Mawg says reinstate Monica Jan 25 '20 at 11:24
  • 4
    Handle such with the Ajax payload, that's what I meant. – πάντα ῥεῖ Jan 25 '20 at 11:25
  • Ah, thanks, just like @hans suggested. Do you have a link to an example? It would help other who read this question in future – Mawg says reinstate Monica Jan 25 '20 at 16:15
  • 11
    What is the actual problem you want to solve? – Thorbjørn Ravn Andersen Jan 25 '20 at 23:55
  • Why would you then still base it on HTTP instead of just building a protocol on top of TCP? – rackandboneman Jan 27 '20 at 16:49
  • 7
    The approach at every place I've worked at in the past decade has been to use a standard content type and message body in the error response. Usually that's JSON, but sometimes it's text/plain, XML, or even text/csv. You can even do binary with protobuf or capnproto or parquet. – ngreen Jan 27 '20 at 17:32
  • 1
    This smells like solving the wrong problem. – Mast Jan 28 '20 at 07:57
  • 1
    Just use a custom header. But I agree with other comments, this feels like an X-Y problem. – Ian Kemp Jan 28 '20 at 09:15
  • DO you reckon that I ought to reword the question to make it less of an [ X-Y problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem), given how long it has been open & how many answers it already has? I don't mind doing so, but am unsure ... – Mawg says reinstate Monica Jan 28 '20 at 10:56
  • If you do, it's no longer HTTP. – Christoffer Hammarström Jan 28 '20 at 12:54
  • 1
    @Christoffer I don't think HTTP/1.1 requires any particular response texts (and I'm reasonably sure I've seen translated response codes in the past fwiw). What would make it violated the standard? (It wouldn't work with http/2 admittedly afaics) – Voo Jan 29 '20 at 16:11
  • Sure you can, but if in the future you'll have to integrate with third parties? What isn't right now could be tomorrow. Nevertheless is there any reason to avoid HTTP standards? – JoeriShoeby Feb 03 '20 at 20:36

4 Answers4

86

The “status text” doesn't exist anymore in HTTP/2. There is only the numeric code. So you won't be able to use HTTP/2 (or later versions).

According to section 8.1.2.4 Response Pseudo-Header Fields of RFC 7540, which specifies HTTP/2:

HTTP/2 does not define a way to carry the version or reason phrase that is included in an HTTP/1.1 status line.

user355880
  • 889
  • 1
  • 4
  • 5
  • 1
    This should be the accepted answer. – Ian Kemp Jan 28 '20 at 09:14
  • 2
    HTTP/2 does not obsolete HTTP/1.1. This is clearly said in the HTTP/2 RFC, that the binary message protocol defined by HTTP/2 is intended as an alternative and not a replacement of HTTP/1.1. – Lie Ryan Jan 28 '20 at 11:38
50

While you may control all the clients and servers, you also has a third end you need to be aware of: the intermediates.

The intermediates are web servers, proxies, caches, web application firewall, load balancer, CDN, and other intermediate systems that processes the HTTP message that may stand between your clients and servers. Even if you use end to end encryption and control all the intermediaries used, it's generally easier to integrate new intermediaries into the system when you stick to the standards.

With that said, unless configured otherwise, standard compliant intermediaries normally should only use status code when deciding how to process the message and should have ignored the reason phrase, so in most cases it should be safe to customise the reason phrase. The reason phrase should be reserved to only carry human readable reason that shouldn't affect how the message should be processed.

Some references from RFC 7231 (Section 6.1) (emphasis mine):

The status codes listed below are defined in this specification, Section 4 of [RFC7232], Section 4 of [RFC7233], and Section 3 of [RFC7235]. The reason phrases listed here are only recommendations -- they can be replaced by local equivalents without affecting the protocol.

And from RFC 7230 (Section 3.1.2) (emphasis mine):

The reason-phrase element exists for the sole purpose of providing a textual description associated with the numeric status code, mostly out of deference to earlier Internet application protocols that were more frequently used with interactive text clients. A client SHOULD ignore the reason-phrase content.


So what should you do instead if standard HTTP status codes aren't sufficient for you?

Use the status code. HTTP Status code is designed to be extensible. Refer to RFC 7231 Section 6 on how to extend HTTP status code in a way that would remain backwards compatible with clients and intermediaries that doesn't understand the extended status code.

Lie Ryan
  • 12,291
  • 1
  • 30
  • 41
43

An alternative approach would be to include a response body containing the detailed failure reason, for example in a JSON object. This would be comparable to the customized 404 pages which are often delivered to browsers when a non-existent web page is opened.

For example, if your backend is written in Python using Django, you could implement a middleware function (see https://docs.djangoproject.com/en/3.0/topics/http/middleware/) to catch exceptions and return a 500 error with some error JSON object (note this is completely untested, just use it to get an idea how it could be done):

import sys, traceback
from django.http import JsonResponse

def exception_handling_middleware(get_response):

    def middleware(request):

        try:
            # call inner handler
            return get_response(request)
        except BaseException:
            # if any exception happens, return an error response
            # with a 500 status code
            return JsonResponse(
              {
                "error": str(sys.exc_info()[1]),
                "traceback": traceback.format_exc()
              },
              status=500)
Hans-Martin Mosner
  • 14,638
  • 1
  • 27
  • 35
-12

By all means use your own codes as the standard HTTP codes really are not that good, but my advice is to keep them separate for maintenance sake and not to confuse anyone who one day may use your code, so rather than 3 digit codes with a decimal point, go with say 5 digit codes

  • 2
    In your answer you state some things like "the standard HTTP codes really are not that good", and that 5-digit codes should be used. Can you provide arguments or sources for these statements? That would make for a better answer. – Tvde1 Jan 27 '20 at 11:31
  • 8
    Using 5 digits code would break [the HTTP standard](https://tools.ietf.org/html/rfc7231#section-6) and any middleware handling the message (proxy, firewall, load-balancer, ESB, CDN, monitor, etc.). If you really need to use custom code, you should stick to 3 digit and respect the first digit meaning (2xx = success, 4xx = client error, 5xx = server error etc.). If you don't do that, your protocol is no longer HTTP compliant and you better be able to justify the need of a custom protocol. – zakinster Jan 27 '20 at 11:38
  • 1
    There's rarely a reason to create a new status code instead of using an existing one and providing additional information via a response body or header. But if you do, follow the standard (but again, rarely the right thing). – Voo Jan 27 '20 at 12:54
  • I'm talking from personal experience on an api they I am currently implementing. My answer clearly stated to keep your personal codes separate from the HTTP codes and the two should not be intermingled. Any codes you return shouldn't interfere with the , existing codes. – Mikesplace Jan 27 '20 at 20:13
  • 1
    This appears to be answering a different question. The question on this page clearly states that they intend to use standard HTTP status code numbers, but vary the textual phrase next to them. – IMSoP Jan 28 '20 at 11:06
  • Voo what if your API is an API of APIs, like mine and on your server the code is 200 in its execution context, but the remote server reported a 404 error. Bubbling up the 404 error, does that really make sense? Personally I don't think it does, that is one example of where I think the existing standard doesn't really work – Mikesplace Jan 28 '20 at 11:39
  • 2
    I don't know exactly your situation in detail, of course, but I'd say that the case of the remote server returning 404 is irrelevant to the client of your API. How your API does whatever it does is none of the my business, so if the remote server 404's, I don't care - I only care about what I asked your API to do, and as far as I'm concerned if your API fails to do it then that's your API failing, not the remote one. If your API can carry on and do its job despite the remote 404, return a 200 and nobody but you needs to know; if it can't, 5xx and maybe some detail in the body. – Richard Ward Jan 28 '20 at 16:31
  • So if my API passed through a request to find a resource on another system via a new API call and it wasn't there the code would be 200 according to your logic, because the intermediary API handled the missing resource error? Even if the initial call was about a resource? Sounds like you haven't thought this one through very much and it sounds like maybe I do have a case for non standard codes – Mikesplace Jan 28 '20 at 20:53
  • @Mikesplace No you misunderstood Richard's point. The point is that whether your service calls another rest service or not is irrelevant to your services public API. What if you change the implementation from a rest call to a WCF call? The extern behavior of your API shouldn't change whether you get a 404 from the other server or a WCF fault. What you should return in this situation depends on your use case, but a 404 could make sense (this is what you have to decide when designing your API). This situation can be handled perfectly fine with the HTTP standard without any extensions. – Voo Jan 29 '20 at 16:05
  • No I didn't misunderstand. For example I am working on a project that has one single method which has several paths of execution on the backend and two different operations and two different types of return data bundled in one object. HTTP status codes don't really cut it so I have database error log I write to and the key is known to the client. Each transaction has a postal address and a user as combo key to the error log. Now if the user doesn't find anything at that address, the purpose of the API, but hit the single method, is it a 404 or not? – Mikesplace Jan 30 '20 at 20:59