REST using the WCF Web API – getting more RESTful responses (Part 5)

Written on April 21, 2011

Postings published on this series so far:

It's about state

A fundamental element of the HTTP protocol is returning the state of the current request in the HTTP headers. When using classic Web or WCF Services there have been made efforts to represent state by sending exceptions over the wire etc.

When taking a close look at the HTTP status codes, you'll see that you can represent every state a request or the server hosting that service (or resource in terms of REST) has by using these status codes.

WCF Web API of course supports using them.

In our next scenario we'll request a specific contact and of course, we want to receive this contact from the response. In addition to that we also want to get "notified" if the contact does not exist or the id used in our request is plain wrong.

First, lets take a look back at our first method we already implemented to pull out a list of all contacts from our server:

[WebGet(UriTemplate = "")]
public List<contact> Get() {
    return _contactRepository.Get().Cast<contact>().ToList();
}

Now we'll create a new resource called ContactResource containing a method Get being able to receive an id by which the requested contact is pulled out of our repository:

[WebGet(UriTemplate = "{id}")]
public Contact Get(int id) {
    return _contactRepository.Get(id) as Contact;
}

Despite the slightly different signature of the Get method we also modified the URI template to map the request parameter id to the methods id parameter.

To make the method return one of our contacts we also tell our configuration in the global.asax about our additional resource by adding the following line:

RouteTable.Routes.MapServiceRoute<contactresource>("contact", configuration);

Pointing our browser to

http://localhost:1413/contact/1

it returns one of our Microsoft guys:

Glenn Block as Xml

Investigating this request/response in Fiddler turns out that the HTTP status code 200 for "OK" has been added automatically to our response:

HTTP/1.1 200 OK

Server: ASP.NET Development Server/10.0.0.0

Date: Wed, 20 Apr 2011 19:41:23 GMT

X-AspNet-Version: 4.0.30319

Content-Length: 91

Cache-Control: private

Content-Type: application/xml; charset=utf-8

Connection: Close

<?xml version="1.0" encoding="utf-8"?>1Glenn Block

Now lets see what happens if the contact we are requesting does not exist by simply using a not existing id:

HTTP/1.1 200 OK

Server: ASP.NET Development Server/10.0.0.0

Date: Wed, 20 Apr 2011 19:48:50 GMT

X-AspNet-Version: 4.0.30319

Content-Length: 116

Cache-Control: private

Content-Type: application/xml; charset=utf-8

Connection: Close

<?xml version="1.0" encoding="utf-8"?>

As you can see, we don't get a contact but still receive HTTP status code 200 -- which of course should be 404 instead for "Not Found" to fulfill the terminology of REST and HTTP. In addition we get a XML fragment we don't want have to deal with.

But where to modify the HTTP status code now?

Fortunately this functionality is contained in the WCF Web API so we just need to modify the signature of our method a little bit and we'll be able to modify the HTTP status inside our method:

[WebGet(UriTemplate = "{id}")]
public HttpResponseMessage<Contact> Get(int id) {
    Contact contact = null;
    contact = _contactRepository.Get(id) as Contact; 
    if(null == contact) {
        return new HttpResponseMessage<Contact>(HttpStatusCode.NotFound);
    }
    return new HttpResponseMessage<Contact>(contact);
}

WCF Web API introduces the HttpResponseMessage class which allows us to take control over the HTTP response being returned whereby we're using a very small part of it in the sample above -- more to come for sure.

Re-invoking our malformed request on

http://localhost:1413/contact/4

in Fiddler, it now returns the expected status code and there's no XML fragment inside the response body:

HTTP/1.1 404 Not Found

Server: ASP.NET Development Server/10.0.0.0

Date: Wed, 20 Apr 2011 20:07:07 GMT

X-AspNet-Version: 4.0.30319

Cache-Control: private

Content-Length: 0

Connection: Close

When speaking of testing again there will be no annoyances. As HttpResponseMessage doesn't have any dependencies requiring any test setup we can implement our test straight forward:

public class Given_a__contact_resource__when_requesting_a_not_existing_contact : WithSubject<ContactResource> {
    static HttpStatusCode _statusCode;

    Establish context
        = () =>
            The<IContactRepository>()
                .WhenToldTo(r => r.Get(4))
                    .Return(null as IContact);

    Because of = () => { _statusCode = Subject.Get(4).StatusCode; };

    It should_return_status_code_404_not_found
        = () => {
            _statusCode.ShouldEqual(HttpStatusCode.NotFound);
        };
}

Put simply: Green ;-)

test result

Having modified the status code of our response according the state of our request in according to REST terminology using native HTTP elements we have taken the next step to a RESTful architecture using the WCF Web API.

Next one will cover creating data on the server using WCF Web API.

Postings published on this series so far:

DotNetKicks-DE Image.aspx&bgcolor=3169AD&fgcolor=FFFFFF&border=000000&cbgcolor=D4E1ED&cfgcolor=000000)