I ran into a problem yesterday. I’d sent a HTTP POST request to a collection of resources on our RESTful web service. Our server responded with an
HTTP 201: Created status code and the URI of the new resource in the
And then… nothing happened.
This was not what I was expecting. I expected my web browser to follow up with a GET request to the URI I’d provided. But Firefox 3 wasn’t biting. A problem with Firefox? I checked in IE8 and Google Chrome and got the same behavior.
Had I misread the HTTP spec? Did I misunderstand the REST pattern? I grabbed for my worn copy of RESTful Web Services. Nope.
HTTP 201 seemed to be the right status for this situation.
Had I blundered into some common error? I checked Stefan Tilkov’s useful list of REST Antipatterns. But I couldn’t find anything that quite matched my situation.
I started Googling, but couldn’t find much apart from this question about HTTP Post on Stack Overflow. There were some cryptic responses (to which I’ve added my own answer now).
The answer is that while web service clients will often “take the hint” provided by a
HTTP 201: Created response, web browsers won’t. If you actually want a web browser to go somewhere else, you need to send a status code in the 3xx series. In this situation, the status code you want is
HTTP 303: See Other.
Once I changed the status code returned by the server, all the web browsers followed up the response with a GET to the new URI.
The question was: What is the best / most flexible way to have WCF output XHTML?
Here’s how we do it at Infovark. While I’m not sure that our approach is the best way, it does the job.
Our approach is to use the DataContractSerilizer to generate XML, then apply a Complied XSLT transform and return the result stream, which should now contain XHTML. Here’s a simplified version of our code:
It works for us, but if you’ve got other, better ideas, please let me know!
I know it’s possible to transmit Internet Protocol by carrier pigeon, but I’m not sure I could recommend it to our customers with a straight face. By the same token, I’m continually surprised to hear vendors and consultants insist that Web Services can be done without the web.
Yet I’ve seen that claim repeated all over the Internet. Sure, it’s true in the academic sense. Technically, there’s nothing wrong with “webless” web services, just like IP by avian carrier will eventually get the job done (though latency and packet loss are a challenge). But practically speaking, why would you use anything other than HTTP?
The “webless web services” meme has infected a number of good ideas. The SOAP standard is a case in point. At first, SOAP was a simple XML wrapper around an XML payload. (Remember when the S in SOAP stood for Simple?) Then a variety of industry heavyweights jumped on the bandwagon, and soon SOAP could be used with any protocol.
Nicholas Allen recently shared a great presentation on REST and SOA given by Stefan Tilkov at QCon. Stefan makes some great points about how RESTful web service design aligns well with the goals of Service Oriented Architecture (SOA).
Sure, you could use the WS-* stack if you like, but RESTful web architecture is a proven, scalable and truly simple approach, as long as you don’t mind having to use HTTP.
Much of the added plumbing in the WS-* stack is there to help transition older computer-to-computer network communication technologies. It allows applications that depend on CORBA or DCOM to tunnel through firewalls. But unless you’re trying to retrofit a system built before, say, 1998, you can skip all that stuff.
Wasn’t using web protocol the whole point of web services anyway? As Stefan said in his closing comments: “Protocol independence is a bug, not a feature.”
Use a RESTful architecture for new development. Put the web back in web services.
The easiest way to explain the issues we encountered when implementing REST is to work through the design principles we followed. I think much of our trouble came from the fact that we come from a web applications background, not a SOAP services background. I’m hoping that by laying out our REST design, some of the Microsoft gurus can help us do things “the WCF way.” And perhaps we can help the WCF team out by highlighting a handful of places where we found WCF unintuitive.
Fundamentally, the REST pattern is about making resources available. This means that each item stored within your system can be accessed by someone with the correct permissions. Every one of these items has its own unique address, and its address should not change. This consistency is important, because it allows both people and computer programs to remember and reference items in your system.
Note that we’re talking about resources or items. In contrast with the SOAP model of web services, which allows programmers to invoke procedures on remote computers, REST is about providing data. SOAP is about verbs, while REST is about nouns. A SOAP service might
CalculateTotalSale(); a REST service provides
CustomerRecieptNo_12345. The kind of web services architecture you use will depend on the kind of application you’re building. The choice has major implications for the other components of your system.
REST imposes restrictions on what sort of things you can do, because it supports only a handful of actions: GET, POST, PUT, and DELETE. (There are a few other HTTP methods, but these four are the most important.) Fortunately, with these four actions, you can accomplish most basic programming tasks. There’s a close parallel to these actions and create/read/update/delete, or CRUD, the building blocks of data storage systems.
Since the address, or URI, is the primary way to access information in your system, it’s effectively part of your user interface. All the principles of good user interface design apply. So when designing a REST service, you need fine control over the structure of these identifiers.
SOAP, by contrast, typically has just one endpoint. The address itself conveys no information about what services are provided — that’s why SOAP services require a separate WSDL file to tell folks what’s possible. With REST, it should be easy to discover the extent of the system by looking at the URIs alone.
Coming up with good REST URI patterns can be tricky. Using short, descriptive naming conventions for your resources makes them easier to type. But URI patterns must also be distinct and unambiguous.
In the .NET framework, you use the UriTemplate class to define patterns. The UriTemplate implementation that shipped with .NET 3.5 allowed you to define variables that fit into slots in your URI. A typical UriTemplate might look like this:
WCF looks for incoming URIs that match the patterns you define. The pattern defined above would match the following URIs:
Once you’ve defined a UriTemplate, you bind it to a method that has the same number of parameters. (I won’t go into the ABCs of WCF here, but you can check out this MSDN Introduction to WCF if you need a refresher.)
In WCF 3.5, you could only define a variable for a whole segment. A segment is basically the bit between the one forward slash and another, or one querystring parameter. A few bloggers requested more flexibility in UriTemplates, and the WCF team answered with the soon-to-be-released 3.5 SP1. The ability to define variables for partial segments was crucial for our URI design.
Most books about web services, including RESTful Web Services, advocate leaving off file extensions from your URIs. This makes sense for SOAP, where you’re accessing methods and all responses are transmitted in XML. But in REST, you’re serving up items.
In our case, some of these items being served were files and some were records from a database. It seemed inconsistent to have some endpoints that had file extensions and others that didn’t. And we also wanted to be able to serve up different representations for our database records. Our REST service supports both JSON, XML, and HTML. It made sense to use a file extension to distinguish between the different representations.
One workaround would have been to create endpoints like
http://restserver/form/1040/xml but that looked funny next to URIs like
http://resterver/file/documentation.pdf. True RESTafarians would point out that neither the “/xml” or the “.pdf” are needed, since you can request an appropriate representation using the HTTP ACCEPT header. We decided against the header approach because not all browsers use the ACCEPT HTTP header. Besides, it might be useful for us humans to be able to reach alternate formats by simply changing the URL in the browser address bar.
In WCF 3.5, this required us to create three times the number of endpoints, with a separate method to handle each. We can’t wait for the official release of 3.5 SP1 to make UriTemplates like
Another source of endpoint duplication was the need to have two different endpoints for
http://restserver/folder/. Because the slash is used as a segment delimiter, the dispatcher in WCF 3.5 saw these two URLs as fundamentally different.
So handling what we thought were fairly trivial cases in URI patterns led us to create FIVE TIMES the number of endpoints we wanted. It’s a maintenance nightmare. SP1 can’t get here soon enough.
I finally figured out the source of my HTTP 400 problem. Apparently the Windows Communication Foundation deals with exceptions differently depending on your InstanceContextMode settings. I had been using the
Single setting but I should have used the
PerCall setting. In PerCall mode, the try/catch block works as expected.
I think it has something to do with the way that WCF distinguishes between channel exceptions and message faults.
Anyway, if you’re building a REST web service, you’ll want to make sure your class is decorated with the following ServiceBehavior attribute.