During my time developing Business-to-Business (B2B) technologies, I saw and continue to see what I feel is a ridiculous pattern of behavior. In this community many systems communicate by POSTing content between systems. As you might expect, there are a number of things that can go wrong so inevitably a system responding to a request will have to send an HTTP Status Code to indicate success, failure, etc. All too often these systems recognize/send only two HTTP Status Codes, namely 200 (success) or 500 (failure). Unfortunately they are usually implemented incorrectly which leads to no end of useless, duplicative, redundant, and inevitably failed communications. Lets walk through a simple scenario to demonstrate exactly what happens.
- Requesting system sends a request with incorrect content
- Receiving system recognizes invalid content and sends a 500 (e.g. Internal Server Error) to indicate failure
If you define the status codes simply as 200 (success) and 500 (failure) this may seem reasonable, but as usual, the devil's in the details. 200 equaling success is generally not in dispute, but lets take a closer look at the definition for 500.
Response status codes beginning with the digit "5" indicate cases in which the server is aware that it has erred or is incapable of performing the request.
- Hypertext Transfer Protocol -- HTTP/1.1 [RFC2616] (http://tools.ietf.org/html/rfc2616#section-10.5)
Note the statement "it has erred". Any system that is compliant with the HTTP standard would read this and think the target system had a problem and retry the same request again immediately, or at a later date. The problem is, the sender is the problem in this scenario... They can resubmit all they like and the result should always be the same. Here is where you start becoming your own worst enemy. Many organizations will create cases around failures like these and follow up, triage, or otherwise investigate because in B2B you never like saying no to any request.
The sad part is; at least in my experience; they end up contacting the requester and telling them to fix their content and not fixing their own system. In a manner of speaking, generating responses that lead to an unnecessary increase in work-load is like defecating in your own mouth. Sure... it's survivable, but no matter how you look at it, it will never taste right. Increased traffic, wasted bandwidth, redundant case load, customer (e.g. requester) frustration, the list goes on. In this case, a better response would be to use the 400 series message.
The 4xx class of status code is intended for cases in which the client seems to have erred.
- Hypertext Transfer Protocol -- HTTP/1.1 [RFC2616] (http://tools.ietf.org/html/rfc2616#section-10.4)
Again... note the statement "client seems to have erred". This would be a more appropriate response to our scenario, a response of 400 would be enough to tell a standards compliant system that the request was not valid and NOT to try again until the request is corrected. Oddly enough, many B2B standards provision for codes beyond 200 and 500 but for some reason they don't seem to follow their own advise. Another common misuse of the 500 code is to send it when a user fails to authenticate or fails to have the authorization level (e.g. permission, right, or role) to perform a given action. In this case, a response of 401 (e.g. Unauthorized) is more appropriate.
For those of you who are thinking this is completely obvious and you would "never" do something so silly, chances are you have already done it and didn't even realize it. Consider the following code:
Response.Redirect(http://www.smelser.net/blog/default.aspx);
On the surface this may look pretty straight-forward. What you may not realize is that under the covers this sends the browser an HTTP Status Code of 307 (e.g. Temporary Redirect). If you have done your research on how web-crawlers work (Internet or Intranet) this kind of response can lead to pages not being indexed. Assuming you actually want to be found, this could be a problem. In my experience, people who use this call rarely mean it to represent a "temporary" redirect, so a more appropriate response would be 301 (e.g. Moved Permanently). As a side note, Microsoft will make this more obvious as part of ASP.NET 4.0 and MVC 2.0 by providing the Response.RedirectPermanent and Response,RedirectToRoutePermanent. In this mean time you can just make your own by writing an Extension Method for the HttpResponse class.
Here is another missed opportunity for those of you who use durable (or reliable) services such as message queues. If you are sure you will never lose a request, and you actually experience a "real" 500 condition (e.g. your service fails), you can respond with a status code of 202 (e.g. Accepted). This tells the requester that you got the request, although you cannot provide a complete answer with respect to its success. If your system (or protocol) has a mechanism to check the status of requests this is ideal because you can process the requests once your system comes back online and they can check for final acceptance at a later date. This can also be useful when you need to take a system offline for maintenance or upgrades.
Consider services that are load balanced. If a slow response is worse than a failed response; due to SLA's, customer experience, or whatever; you may want to have your server/application send a signal that tells your load balancer to send a request to another available server. For many load balancing products this can be as simple as sending a response code of 503 (e.g. Service Unavailable). Again, this could be useful when performing upgrades or maintenance.
So what does this all mean? Take a closer look at the standard codes and do your best to align to the them. It may be a little additional development, but in the end it will save you a lot of time and money. For a summary of the basic status codes, take a look at http://en.wikipedia.org/wiki/List_of_HTTP_status_codes.
Tags: design patterns