Why you should not use RPC for GET

This article will describe in simple terms why it is inappropriate to use RPC methods in general and RPC methods running over HTTP POST (i.e. SOAP RPC or XML-RPC) to implement getter methods.

Let's first define a getter method as a method that has no side-effects and exists only to return information based on a network address (e.g. IP address or URI) and parameters. For instance consider the RPC-over-HTTP way of getting a stock quote:

POST /quotes.aspx HTTP/1.1
host: www.stockquotes.com

<envelope>
  <body>
     <quotename>FLOX</quotename>
  </body>
</envelope>
       

Now consider the more traditional HTTP way:

GET /quotes?quotename=FLOX HTTP/1.1
host: www.stockquotes.com

The HTTP way is better in every way, shape and form. Obviously it is shorter and easier to read on the wire. But that's the least interesting of its advantages.

Advantage 1: Globally standardized address space

The HTTP way gives the information a globally standardized address. You can give that URI address to anyone, anywhere and they can reuse it. In particular this means that we can compose applications that were not thought of in advance. Google is an example of an application that was composed "after the fact" out of URIs. Yahoo is another. AmIHotOrNot.com is another. Meerkat is one based upon XML, rather than HTML.

In fact, to one extent or another, most interesting web services (in the old fashioned sense) have some degree of this kind of "extreme late binding." Newer, XML-based linking technologies like RDF and topic maps make this idea of third-party applications built on top of HTTP addresses even more compelling and amazing.

For more information on the benefits of unifying namespaces, consider the writings of Hans Reiser of ReiserFS fame:

The utility of an operating system is more proportional to the number of connections possible between its components than it is to the number of those components. Namespace fragmentation is the most important determinant of that number of possible connections between OS components.

Leveraging Web Tools

There are a raft of deployed W3C recommendations that work with information related through URIs. Many of these are XML-related specifications that work as well in API-like applications as in user interface-based applications. These include:

Information published through HTTP URIs can be combined through XInclude, queried and sorted through XQuery and XSLT, visually rendered with xml-stylesheet, related through RDF, linked through XLink, pointed into through XPointer.

Integration Interoperability

Consider if all of the financial companies in the world standardize a way for representing a company's trading performance for a single day (high, low, volume, etc.). Now imagine I write a piece of software that allows them to visualize this information. Maybe I use antarti.ca's data visualization technology and RDF. (I use this example because I believe it does work with RDF)

Now I want to sell this product to you. The HTTP way of "integrating" this application with your internal systems is to generate an XML file with a bunch of URIs for each document to be visualized. My product can spit out RDF with a bunch of annotations pointing to the documents and the 3D software can do is rendering based on that.

The RPC way of "integrating" these applications would be to write a bunch of code that maps between the 3D software's API and the purchase order system's API. When either API changed, the software would change, even if the XML vocabularies did not. Whereas the HTTP system is API-less so that is one less thing that can change or break.

Common complaints

The URI way of doing things is exactly as flexible as the RPC way. URI parameters can be arbitrarily complex, just as RPC input parameters can be. But it is actually quite rare for these parameters to become very complex. Once they start to become so it makes more sense to "reify" the query as its own resource with a URI and pass that URI as an input.

You might think that the RPC way is better because in code it probably looks more like a method call. Actually this is not necessarily true. We can make the URI-way look like a method call in code if we just install a small configuration file that maps from method calls on objects to URIs. One language for defining these mappings (as well as doing other cool things) is called WRDL. Here's what code using it might look like:

# new WRDL way
stockserver = WRDL.bind("http://www.stockserver.com/stock.wrdl",
                        "http://www.stockserver.com/stocks")
stocknum = stockserver.GET(stock="FLOX").body

# older XML-RPC way:
stockserver = XMLRPCServer("http://www.stockserver.com/stocks")
stock = stockserver.getStock("FLOX")

Handling updates

Now once you've reified each stock as a resource then maybe it makes sense to ask whether you could update it by PUT-ting to it. Well you probably don't have the authority to unilaterally set prices on the stock market (or if you do, pleae contact me). But perhaps your job is to tell the stock quote server what the current price is on the trading floor. In that case it would make perfect sense to PUT to it. And if a symbol is delisted then of course you could DELETE it.

Let me deal with a common question: what if the input query is really long and it will blow up some server's URL buffer or something? If your application has a need for that then there are various HTTP workarounds. But it is important to realize that this is an extremely rare case and it is not a good idea to choose to use an RPC protocol merely to deal with this rare case. If you run into this case then go ahead, use RPC for that one case. It happens so rarely that I won't bother to try to talk you out of it. My only request, however, is that you think carefully about whether the input query is really very long or whether you just haven't thought it through enough to invent a compact URI representation for it? Consider:

SELECT name, age from customers where customers.age > 65

(I haven't done SQL in a while...please forgive me if the syntax is broken...shoot me an email with a fix if you are inclined)

You might think this is going to be a pretty ugly URI. The trick is to remember that the web has its own data model, just as SQL does. You would never expect a database to be able to do anything with a URI unless you translated it into SQL, so you shouldn't expect the Web to deal with SQL unless you translate it into a URI.

GET /customers?agemin=65&return=name+age

As long as you provide a URI-addressable way to get at your data of course there is no harm in also providing an RPC interface. But once there is a way to get at the structured data through HTTP, it may not be that useful to also add an RPC interface. It's up to you.