• Feeds

    Subscribe in a reader

  • Ads

Programming Model for HTTP Status Codes

In my last post on HTTP/POX basics, Dave Bettin asked a good question in the comments:

Will you guys have a good story around a programming model for associating HTTP status codes with CLR exceptions? Or are we stuck with the existing fault model?

The short answer is "of course we'll have a good story around programming HTTP status exceptions!" We haven't landed on whether that model will be based on exceptions or not.

Exceptions are a nice control flow abstraction for doing non-local jumps out of a method body (which is sometimes what you want with status codes, but not always). The downside is that they're relatively expensive from a performance perspective -- hence the general guidance of "don't use exceptions for non-exceptional circumstances".

Personally, I don't think that any of the HTTP status codes are truly exceptional (with the possible exception of HTTP 500, which means the server barfed). Everything else (including Endpoint Not Found[1] is pretty de regeur for a server on the Internet.

At small/medium scales, you can get away with making the making a performance tradeoff that optimizes the mainline success path at the expense of the "error path" because you can assume that most people will play by the rules. You can't make that assumption on the Internet -- you can't assume that everyone's going to get the URL right, for example. As such, you'd really like to get mainline performance out of your negative paths if at all possible -- if you don't, you've got what amounts to a potential DOS vector.

So instead of exceptions, we're looking at a slightly different model based around the notion of "setting status" on the current response. We haven't closed on the final form for this yet, but the current thinking is something like the following:

     TransferContextThingy.SetStatusOk();
     TransferContextThingy.SetStatusCreated( Uri location );
     TransferContextThingy.SetStatusRedirected( RedirectType t, Uri u);
     TransferContextThingy.SetStatusNotFound();
     TransferContextThingt.SetStatus( System.Net.HttpStatusCode status, string description );
     ...

Obviously, this is not a complete set and TransferContextThingy is a temporary name but you get the picture.

Here's how this might get used in practice:

   public Customer GetCustomer(int id)

   {

        Console.WriteLine("Received GET for " + TransferContextThingy.Request.RequestUri);

 

        Customer customer = null;

        customerList.TryGetValue(id, out customer);

 

        if (customer == null)

        {

            TransferContextThingy.Response.SetStatusNotFound();

        }

 

        return customer;

   }

How does that look?

[1] Yes, I know we have an EndpointNotFound exception in WCF already. However that's really only thrown on the client, not the server.

#1 Brian Vargas on 3.06.2007 at 7:08 AM

There is a big problem with requiring programmers to set response codes in that manner:It leads to impossibly difficult code.The GetCustomer() example is trivial, so it doesn't look so bad, but when you put your error condition at the top of a twenty-deep callstack, you've now forced every calling function to check (essentially) return values.If they were worried about the cost of a stack unwind, wait until they do all their database work and then throw it away at the end because there was a a non-200 response code.Worse, it could lead to accidental data changes.Programmers like to code for the common case - and they'll do it no matter how you plead with them not to.I think you're falling into the COM+-is-better-than-Java trap, circa 2001.That is: Sure, its faster and has better enterprise integration; but 95% of the developers out there don't /need/ that.They need a good tool to improve their productivity.The ideal situation, of course, is to provide both tools.One based on status codes, and one based on exceptions.I suppose nothing prevents a developer from throwing their own exceptions if they need to; but again, that's the 5% who are smart enough to know the difference, and they'd have done it right anyway.

#2 Steve Maine on 3.08.2007 at 12:04 AM

That's a reasonable arugment. But do you really want to be throwing EndpointNotFoundException() from deep inside your data access layer? It seems like you'd want to throw an application-specific exception and then translate them to status codes in some top-level exception handler. Of course, implementing an exception->exception mapping is a common pattern for exception handlers in general, and having HTTP status code exceptions would make our stuff easier to use in those scenarios...

#3 mike on 3.11.2007 at 4:50 AM

Of course, implementing an exception exception mapping is a common pattern for exception handlers in general ..what thats mean?

#4 Mark Baker on 3.27.2007 at 2:41 PM

"It seems like you'd want to throw an application-specific exception and then translate them to status codes in some top-level exception handler."Bingo.Anything else would be a horrible separation of concerns (breaking layering).Yes, abstraction comes at a cost (performance), but IME, it's not very much in the general case if you're just using a Web server rather than a Web server and app server.

#5 翻译公司 on 4.27.2007 at 2:34 AM

Hi! Guys how you manage to make such perfect sites? Good fellows!

#6 Chat on 5.03.2007 at 8:16 AM

That's a reasonable arugment. But do you really want to be throwing EndpointNotFoundException() from deep inside your data access layer? It seems like you'd want to throw an application-specific exception and then translate them to status codes in some top-level exception handler.Of course, implementing an exception->exception mapping is a common pattern for exception handlers in general, and having HTTP status code exceptions would make our stuff easier to use in those scenarios...