Using HTTP status codes in a REST service

When we build services, or write any code for that matter, error can occur and we have to cater for those. With SOAP service we gibe a calling application information about the error by returning a SOAP fault. This SOAP fault is just another piece of XML informing the calling application about whatever was wrong. Now the HTTP protocol also contains a way of sending status information back to the client but when using SOAP that is mostly ignored, all we use is a 200 OK or an 500 Internal Server Error error status. And for one returning a 500 Internal Server Error is really a shame if the error is actually a client problem. But there are far more status codes we can use.


When we are building REST service we embrace HTTP and as a result we also embrace all the HTTP status codes, not just 200 and 500. And that doesn’t just mean with errors but also when everything works as expected as there is a whole range of status codes dealing with success.

In general status code are grouped into a few different categories:

  • 1xx is all about information
    These are not used a lot.
  • 2xx is all about success
    Whatever the client tried to do was successful up to the point that the response was send. Keep in mind that a status like 202 Accepted doesn’t say anything about the actual result, it only indicates that a request was accepted and is being processed asynchronously.
  • 3xx is all about redirection
    These are all about sending the calling application somewhere else for the actual resource. The best known of these are the 303 See Other and the 301 Moved Permanently which are used a lot on the web to redirect a browser to another URL.
  • 4xx is all about client errors
    With these status codes we indicate that the client has done something invalid and needs to fix the request before resending it.
  • 5xx is all about service errors
    With these status codes we indicate that something went wrong in the service. For example a database connection failed. Typically a client application can retry the request. The server can even specify when the client is allowed to retry the command using a Retry-After HTTP header.


A few success status codes:

  • The 200 OK is the generic success status when there is nothing special to report.
  • The 201 Created status is used to indicate that a new resource has been created. This response usually also contains a Location header to indicate the URL of the newly created resource.
  • The 204 No Content is used when we conditionally retrieve some data. For example when using an ETag and asking for the data only if it has been modified using the If-None-Match HTTP header.

A few client failure status codes:

  • A very common client failure status code happens when the client fails provide it’s credentials for a secured service. In that case the service would return a 401 Unauthorized status. The service response will also contain a WWW-Authenticate header informing the client of the way it wants it to authenticate.
  • Another common failure is when the client application asks for some non existent resource. In that case a 404 Not Found status is returned to the client.

A few service failure status codes:

  • The generic service side error status is the 500 Internal Server Error which doesn’t give the client a lot of information Sad smile
  • Another useful status code is the 503 Service Unavailable informing the client application that the service can’t be used at the moment. This could be for any number of reasons but for example because the database used is in a backup procedure. Typically the service also adds a Retry-After HTTP header if it can to indicate to the client that it can retry after a specific period.

Check here for a complete list of all HTTP status codes.


Using HTTP status codes with the WCF Web API

returning custom HTTP status codes with the WCF Web API is quite easy. Lets start with the following very simple example function:

[WebGet(UriTemplate = "/{id}")]

Book GetBook(int id)


    var result = _repo.GetBook(id);

    return result;


If I request the books resource using the URL http://localhost:28330/books/1 I get the following.


That’s just fine and exactly what I would expect. However if I use the URL http://localhost:28330/books/999 to get a book with id 999 which doesn’t exist I see the following:


Not exactly what I want, there is no book found and yet it returns a null book resource.

The fix is quite simple. If we want more control over the response we don’t just return the resource but we return a HttpResponseMessage<T>. Using the HttpResponseMessage<T> we can set all sorts of headers but in this case we are only interested in setting the HttpStatusCode to NotFound if the requested book doesn’t exist.

[WebGet(UriTemplate = "/{id}")]

HttpResponseMessage<Book> GetBook(int id)


    HttpResponseMessage<Book> result;

    var book  = _repo.GetBook(id);

    if (book != null)


        result = new HttpResponseMessage<Book>(book);




        result = new HttpResponseMessage<Book>(HttpStatusCode.NotFound);


    return result;



When we try the same URL again with the new function we get the following result:


Note that Internet Explorer is focused on web pages not books so it tells us that the webpage is not found and the page header contains the actual HttpStatusCode returned, 404 Not Found in this case.

Besides setting the HttpStatusCode instead of a resource in the constructor we can also set it as a property like this:

result.StatusCode = HttpStatusCode.Created;

Just remember that setting a resource, even a null one, will return that to the calling application so in this case where we want to make sure there is no body we have to be very explicit about it.





Leave a Reply

Your email address will not be published. Required fields are marked *