http

HTTP Status Codes in ASP.NET Web API - A Guided Tour

Good morning everyone, and welcome to the new HTTP Status Codes in ASP.NET Web API tour here at Exception Not Found! My name is Reggie, and I'll be your tour guide today. Those of you who have taken our Exception Handling tour, welcome back! For those of you who are new to our facility, thank you for visiting us.

A guide leads a crowded tour of a museum. WikCon UK 2012 Science Museum tour 6 from Wikimedia, used under license

First off, I'd like to introduce my brilliant assistant Postman, who will be assisting me on this tour. Also assisting us will be Nathan, and he'll be doing whatever I need him to, and he better be grateful, this is his last chance, that little...

As I said, Nathan will be assisting us, since we have such a large group. This tour moves fast, so please keep up. Today, we're going to take a look around at the variety of status codes we can return from our Web API applications. Step right this way, stay together, and let's learn about what HTTP status codes are and how we use them in our ASP.NET Web API projects.

The Types of Status Codes

HTTP implements a wide variety of status codes, which are grouped into five categories. The five categories are distinguished by the code's first number, like so:

  • 1XX Codes: Informational codes. Rarely used in modern web apps.
  • 2XX Codes: Success codes. Tells the client that the request succeeded.
  • 3XX Codes: Redirect codes. Tells the client that they may need to redirect to another location.
  • 4XX Codes: Client Error codes. Tells the client that something was wrong with what it sent to the server.
  • 5XX Codes: Server Error codes. Tells the client that something went wrong on the server's side, so that the client may attempt the request again, possibly at a later time.

ASP.NET Web API can return any of those codes, though the more common ones have simpler return methods. Up next, we will show how we can determine what the proper code is to return from our action methods. This way, please.

Selecting the Proper Code

You should know that there is no "one true way" of selecting the proper status code; it all depends on your business rules. That said, unless your rules state otherwise, it is usually a good idea to return a more specific code rather than a more generic one.

As an example, consider a situation where your server needs to tell the client that a request that was submitted to it didn't have the proper authorization. One status code you could return is 400 Bad Request, as this implies that the request submitted was improper and not processed by the server. However, a more specific error code would be 401 Unauthorized, since that explicitly states what was wrong with the request. You should use more specific codes unless you have a business or security reason not to.

So, now we can start talking about what ASP.NET Web API does when it implements actions. If you'll just follow me to the next hallway, we can start to see code that shows what Web API will do in certain common situations.

Return Void - 204 No Content

Nathan, not that display case. Go to the other one. No, the other other one. YES THAT ONE.

Ahem! Take a look at the display case next to where Nathan is standing. Inside, we have one of our sample controllers:

public class MovieController : ApiController  
{
    [HttpPost]
    [Route("movies/add")]
    public void Add(string title, DateTime releaseDate, int runningTime)
    {
        Movie movie = new Movie()
        {
            Title = title,
            ReleaseDate = releaseDate,
            RunningTimeMinutes = runningTime
        };

        //Save movie to a data store
    }
}

You'll notice that this controller only has one action, which returns void. Postman, can you show us what the response looks like when we call this action please?

A Postman response, with the highlighted status code of 204 - No Content

When we call this action, we'll see that ASP.NET returns a status code of 204 - No Content. Since HTTP doesn't understand void, this is the appropriate status code. One of the many features we provide, at no extra charge!

But, what happens if we want to return something a little more complex? If you'll follow me right over here, we can see a sample.

Return Object - 200 OK

Nathan. NATHAN! Quit staring at that butterfly and get over here.

Excuse me. Now, take a look at this action:

[HttpGet]
[Route("movies/all")]
public List<Movie> GetAll()  
{
    List<Movie> movies = new List<Movie>()
    {
        new Movie()
        {
            Id = 1,
            Title = "Up",
            ReleaseDate = new DateTime(2009,5,29),
            RunningTimeMinutes = 96
        }
        //Create some other movies
    };

    return movies;
}

Now our action is returning an object. Postman, what kind of response do we get when calling this action?

A Postman response, with the highlighted code of 200 - OK

Now we get 200 - OK as the status code. But we didn't tell ASP.NET to return this code, so why did it?

Because if you return any serializable object from a Web API action, the response automatically becomes 200 - OK, with the object written in to the response body. Of course, if you wanted to explicitly specify that return code, all you would need to do is change the return type and return statement, like so:

[HttpGet]
[Route("movies/all")]
public IHttpActionResult PinkElephantsOnParade()  
{
    List<Movie> movies = new List<Movie>()
    {
        new Movie()
        {
            Id = 1,
            Title = "Up",
            ReleaseDate = new DateTime(2009,5,29),
            RunningTimeMinutes = 96
        }
        //Create some other movies
    };

    return Ok(movies);
}

Nathan you little animal I'm gonna....

Pardon the action name, we seem to have had a little... difficulty in setting up this display. Rest assured, whatever you name the action, you can use the shortcut method Ok() to return the status code 200 - OK.

Let's hurry along to the next display cabinet, where we will see some other shortcut methods we can use to represent commonly-returned status codes.

Shortcut Methods

I've been using the term "shortcut methods" to refer to a set of methods that return classes which implement IHttpActionResult. The next display cabinet has a few others, each of which represent common HTTP status codes:

  • BadRequest(): Returns 400 - Bad Request.
  • NotFound(): Returns 404 - Not Found.
  • InternalServerError(): Returns 500 - Internal Server Error.

There's also a catchall method, one that can return any HTTP status code:

  • StatusCode(HttpStatusCode statusCode): Returns the specified status code.

HttpStatusCode is an enumeration, whose values can be found over in the Status Codes exhibit. As you see at later points in this tour, HttpStatusCode becomes very useful when trying to return other, less common status from your API.

For now, let's continue down this hallway to see another method by which we can return status codes.

HttpResponseMessage

Though the shortcut methods are useful for common scenarios, they don't cover all possible status codes.... My apologies, please wait here a moment.

Nathan! Mrs. George does NOT need to be shown to the "bodily functions" display. No, it is not "interesting" or "transformative" it is gross and it doesn't even belong to this museum. Now come here! I swear, if your mother wasn't my sister...

As I was saying, the shortcut methods don't cover all possible status codes. For example, the red display in front of you has a method that should return 304 Not Modified:

[HttpGet]
[Route("movies/notmodified")]
public void NotModified()  
{
    //How do we return 304 Not Modified?
}

But there's no shortcut method for that return code, so how do we return it? We use HttpResponseMessage, like in the green display:

[HttpGet]
[Route("movies/notmodified")]
public void NotModified()  
{
    return new HttpResponseMessage(HttpStatusCode.NotModified);
}

HttpResponseMessage represents the response from the server to the client, and can be used with any of the status codes in the HttpStatusCode enumeration. In this way, we can return any of the standard status codes.

Nathan, that does not include 420, that's not a standard code and only one company uses it, stop changing the display!

HttpResponseMessage is perfect for returning status codes that aren't errors, but for the exception handling, there's a more appropriate solution: HttpResponseException.

HttpResponseException

Earlier, we talked about how it is important to select the appropriate status code when returning from an action in Web API projects. Consider the action in the next display:

[HttpGet]
[Route("movies/error")]
public void Error()  
{
    throw new NotImplementedException();
}

NotImplementedException is a .NET Exception that specifies that a given method is not implemented. However, HTTP does not understand .NET exceptions, so Web API will return an error code to a client that calls this method. The error code returned is 500 - Internal Server Error.

We like to say that returning 500 is the equivalent of the server throwing up its hands and saying "well, that didn't work." In other words, it's not a very useful status code. For situations where you don't want to give extra information to client (e.g. public-facing services that could be hit by malicious users) this may be exactly what you want. However, in many other scenarios there is a more appropriate status code to return: 501 Not Implemented.

We can do that by changing the action to look like this:

[Route("movies/error")]
[HttpGet]
public void Error()  
{
    throw new HttpResponseException(HttpStatusCode.NotImplemented);
}

HttpResponseException is a .NET class that translates to an HTTP status code. You can see how else we might handle exceptions with error codes on the Exception Handling tour.

Summary

In short, let's remember the following things about HTTP status codes in Web API projects:

  • Always return the appropriate status code, however you define "appropriate".
  • Use the shortcut methods (e.g. Ok(), NotFound(), etc.) when possible.
  • An action that returns void will send status code 204 No Content.
  • An action which returns an object will send 200 OK.
  • Use HttpResponseMessage for status codes that are not supported by shortcut methods.
  • Use HttpResponseException for error status codes.

Once again, thank you to Postman for your help on this tour (and go download it if you haven't already). For more information, see ASP.NET Web API 2: Building a Restful Service from Start to Finish by Jamie Kurtz and Brian Wortman, specifically Chapter 2, "What is RESTful?". You can find that in the bookshop, it's to your right on the way out of the building.

We hope you have a pleasant rest of your day, and please, come see us again!

Nathan! For the last time, get OUT of the restroom! I know you're not using it for its intended purpose, and the smell never comes out! Your mother will hear of this! You'll be sorry, young man!

Using HTTP Methods (GET, POST, PUT, etc.) in Web API

My group has been studying ASP.NET Web API for a major project we're working on, and part of learning about this tech stack is studying how HTTP works, which has been a nice refresher for us. A couple of my teammates asked me to clarify the HTTP Methods (e.g. GET, POST, PUT, DELETE, etc) we were going to use for specific actions, and I wanted to learn more about them. Hence, this post. Come along with us as we learn about HTTP methods (also called verbs) and discuss how and when to use them in our Web API projects!

What Are HTTP Methods?

Whenever a client submits a request to a server, part of that request is an HTTP method, which is what the client would like the server to do with the specified resource. HTTP methods represent those requested actions. For example, some commonly-used HTTP methods will retrieve data from a server, submit data to a server for processing, delete an item from the server's data store, etc. For a more general overview of HTTP, see Tutorials Point's article.

Selecting The Appropriate Method

A large portion of application functionality can be summed up in the acronym CRUD, which stands for Create, Read, Update, Delete. There are four HTTP methods that correspond to these actions, one for each, like so:

C - Create - POST
R - Read - GET
U - Update - PUT
D - Delete - DELETE

So, in a given app, you might have the following action:

public IHttpActionResult Add(string title)  
{
    //Creates a Movie based on the Title
    return Ok();
}

We can tell from the name of the action (and, let's be real, the comment) that this action is supposed to create a movie. So we should use the POST verb on this action, like so:

[HttpPost]
public IHttpActionResult Add(string title)  
{
    //Creates a Movie based on the Title
    return Ok();
}

If you need a particular action to support more than one HTTP method, you can use the [AcceptVerbs] attribute:

[AcceptVerbs("POST", "PUT")]
public IHttpActionResult Add(string title)  
{
    //Creates a Movie based on the Title
    return Ok();
}

For the majority of applications, GET, POST, PUT, and DELETE should be all the HTTP methods you need to use. However, there are a few other methods we could utilize if the need arises.

  • HEAD: This is identical to a GET request, but only returns the headers for the response, not the response body. Theoretically faster, commonly used for checking to see if a particular resources exists or can be accessed.
  • OPTIONS: Returns the HTTP methods supported by the server for the specified URL.
  • PATCH: Submits a partial modification to a resource. If you only need to update one field for the resource, you may want to use the PATCH method.

POST vs PUT

POST and PUT are very similar in that they both send data to the server that the server will need to store somewhere. Technically speaking, you could use either for the Create or Update scenarios, and in fact this is rather common. The difference lies in the details.

PUT is idempotent. What this means is that if you make the same request twice using PUT, with the same parameters both times, the second request will have no effect. This is why PUT is generally used for the Update scenario; calling Update more than once with the same parameters doesn't do anything more than the first call did.

By contrast, POST is not idempotent; making the same call using POST with same parameters each time will cause two different things to happen, hence why POST is commonly used for the Create scenario (submitting two identical items to a Create method should create two entries in the data store).

(It should be noted that, strictly speaking, HTTP does not force PUT to be idempotent, so you can implement your server to use PUT in a non-idempotent way. However, doing so is liable to cause a horde of angry server admins to show up at your desk and beat you with ethernet cables. Don't say I didn't warn you.)

Default HTTP Methods

If we do not assign an explicit HTTP method to a controller action, what method(s) does that action accept? Let's imagine we have a Web API controller like so:

public class MovieController : ApiController  
{
    /// <summary>
    /// Returns all movies.
    /// </summary>
    /// <returns>A JSON list of all movies.</returns>
    [Route("movies/all")]
    public IHttpActionResult All()
    {
        List<Movie> movies = new List<Movie>()
        {
            new Movie()
            {
                Id = 1,
                Title = "Up",
                ReleaseDate = new DateTime(2009,5,29),
                RunningTimeMinutes = 96
            },
            new Movie()
            {
                Id = 2,
                Title = "Toy Story",
                ReleaseDate = new DateTime(1995, 11, 19),
                RunningTimeMinutes = 81
            },
            new Movie()
            {
                Id = 3,
                Title = "Big Hero 6",
                ReleaseDate = new DateTime(2014, 11, 7),
                RunningTimeMinutes = 102
            }
        };

        return Ok(movies);
    }
}

We can tell by looking at the code that this should be a GET action, since it is returning data. However, we're not explicitly saying that GET should be used (there's no [HttpGet] attribute). So, what method(s) will this action accept? Let's see what Postman can tell us.

It should be a GET action, so let's try to hit this action with a GET request.

Well, that didn't work, we get back a 405 Method Not Allowed status. Why were we not able to use the GET method?

The algorithm ASP.NET uses to calculate the "default" method for a given action goes like this:

  1. If there is an attribute applied (via [HttpGet], [HttpPost], [HttpPut], [AcceptVerbs], etc), the action will accept the specified HTTP method(s).
  2. If the name of the controller action starts the words "Get", "Post", "Put", "Delete", "Patch", "Options", or "Head", use the corresponding HTTP method.
  3. Otherwise, the action supports the POST method.

We're falling in to the #3 condition here: the action name All() doesn't contain any of the key words and we didn't specify an action, so this action will only support POST. Sure enough, guess what Postman shows for a POST action?

Obviously, this is not what we want. We're getting data from the server using a POST method, and this (while not technologically prevented) is not what these HTTP methods were designed for.

We could solve this problem in two ways. The first would be to add the [HttpGet] attribute to the method. The second would be to rename the method to GetAll(); the existence of the word "Get" at the start of the method tells ASP.NET to accept a GET HTTP method on this action. My personal preference is to always explicitly state which HTTP method is accepted by any action, like so:

public class MovieController : ApiController  
{
    /// <summary>
    /// Returns all movies.
    /// </summary>
    /// <returns>A JSON list of all movies.</returns>
    [Route("movies/all")]
    [HttpGet] //Always explicitly state the accepted HTTP method
    public IHttpActionResult All()
    {
        //Get movies
        return Ok(movies);
    }
}

Summary

Always use the appropriate HTTP action in your Web API actions, as it establishes the kinds of communication your consumers can conduct with your app. Further, always explicitly state what HTTP method(s) each action can accept, and keep to the common definitions for each action (e.g. GET for data retrieval, POST for creating data, PUT for updating data, etc.).

For more information, check out ASP.NET Web API 2: Building a Restful Service from Start to Finish by Jamie Kurtz, specifically Chapter 2, "What is RESTful?" and Chapter 5, "Up and Down the Stack with a POST".

Happy Coding!

HTTP 418 I'm A Teapot - Just A Joke, Or Something More?

I stumbled across an interesting StackOverflow thread earlier this week. I had to read it a few times to notice what bothered me: it turns out that there is a status code for HTTP 418 "I'm a teapot". Why in the world would HTTP need such a status code? I'd never heard of this before, and it got me wondering: whoever thought this up, and why? Were they trying to make a point, or just having a little fun? What does it mean?

Nothing, as it turns out. Or maybe it does mean something. Come along with me as I dive headfirst into a silly (or not-so-silly) Internet joke and try to work out if it has any deeper meaning.

A poster, showing a kitten in a teapot, with a caption 418 - I'm a teapot by girliemac, used under license

Brewing Coffee with HTTP

HTTP 418 I'm a teapot was specified in a document called RFC 2324 in 1998, published by the Internet Engineering Task Force (IETF). RFC 2324 describes the implementation of a Hyper Text Coffee Pot Control Protocol (HTCPCP), which extends HTTP and "permits the full request and responses necessary to control all devices capable of making the popular caffeinated hot beverages". The document justifies extending HTTP like so:

HTTP 1.1 ([RFC2068]) permits the transfer of web objects from origin servers to clients. The web is world-wide. HTCPCP is based on HTTP. This is because HTTP is everywhere. It could not be so pervasive without being good. Therefore, HTTP is good. If you want good coffee, HTCPCP needs to be good. To make HTCPCP good, it is good to base HTCPCP on HTTP.

(Seriously, read the whole thing, the justifications it uses are hilarious to anyone with a working knowledge of how the Internet is constructed).

RFC 2324 thoroughly describes the process of brewing coffee via HTCPCP, right up to and including the kinds of error codes the specification can return:

418 I'm a teapot

Any attempt to brew coffee with a teapot should result in the error code "418 I'm a teapot". The resulting entity body MAY be short and stout.

The whole document reads like a big joke, a gag that the IETF is in on (which makes sense, considering it was released on April Fools' and the IETF has a history of publishing such things). Of course, the Internet responded in kind, with varying "implementations" of the protocol, including ones by Google and StackOverflow. Node.js supports it natively, and Mozilla has a long-standing bug that asks for full support of the HTCPCP standard.

So, clearly, the rest of the web is in on this little joke too. And that's all this is: a joke. Right?

Maybe not.

Joke, Or Satire?

The author of RFC 2324 is Larry Masinter, who on his personal page added a little footnote in which he described the protocol as:

...An April 1 joke with a serious purpose -- to spoof ways in which HTTP had been extended inappropriately.

This is all the information I could find about what he meant to show by writing this document, so it's difficult to determine what he actually wanted to accomplish by writing this RFC (if, indeed, he intended to accomplish anything other than making a joke). He seems to express regret that HTTP is being extended so widely, without much thought as to why any of these new status codes should exist. But what does he mean by "inappropriately"?

As best as I can tell, Masinter's purpose in writing this RFC was to point out the dangers of over-extending HTTP for increasingly-specific purposes. We don't need an HTTP derivative specifically for brewing coffee anymore than we need an HTTP derivative for a vending machine. In essence, Masinter's warning was that we should avoid making implementations that are too specific to our domain, because in doing so we reduce the amount of reusability the solutions have, thereby forcing other people to reinvent the wheel if they encounter a similar problem in a different domain. He intended RFC 2324 to be satire, not just a joke.

To be perfectly clear, I'm extrapolating a lot of Masinter's intent from a single sentence, and I could be way off the mark. But I think he was hitting on a common problem in software development: the tradeoff between a given implementation being specific enough to fit the domain vs. being generic enough to solve a wide variety of problems. Seems to me that Masinter was in favor of the more generic solution, and given that HTTP is a critical piece of infrastructure for the Internet, it's hard to find fault with his (supposed) stance.

So, where does that leave us with HTTP 418 and it's supposed deeper meaning? In my humble opinion HTTP 418 is a joke, but one that comes with a relatable message: don't built a hyper-specific implementation when a more generic one will do just fine.

Or it could be just a joke. In which case, you can bet that the next Web API project I build will handle this code. Better keep an eye out, future service clients!

UPDATE 11/2/2015: I posted an off-the-cuff question on Twitter and got a response from Larry Masinter himself!

Happy Coding!