STREST APIs come with specific costs which could stifle
the two-way data Web (Web2.0) if allowed to propagate
unchecked. Although 'mashability' is a supposed benefit of the
current proliferation of APIs, true interoperability and
scalability can only be guaranteed by true REST interaction.

This is not an academic, purist or aesthetic stance, but one
based on practical consequences, as I will explain.

STREST APIs are easy to spot. Look out for one or more of the
following:

Single URLs to GET and POST to - the 'service' endpoint (http://www.flickr.com/services/rest/).

POSTing an entire 'function call' in XML, complete with name and arguments, to the service URL

Note that we're not talking about the lack of PUT and
DELETE here, nor any concept of URL opacity. You can REST
easy without PUT or DELETE and with totally random-looking
URLs.

What we see here is a straightforward hijacking of the HTTP
protocol to use it as a function call protocol. Hijacking and
abusing HTTP isn't REST.

And it comes with a number of costs...

STREST Breaks the GETable Web

By way of showing an exception that proves the rule, suppose
we have the following:

GET http://strest.com/api?call=getPic&pic_id=42

In other words, the function call 'getPic(pic_id=42)'.

Now, this is the one case that works OK - that's really RESTable.
It looks odd as a function call (better as
http://restful.com/pics/42), but you can still cache it,
bookmark, index and link it.

However, look how easy it is to break things once you start
thinking in function calls.

Many APIs ask you to put a special access key in as the first
argument. Throwing needed data into the arguments list is quite
normal in the land of functions. But here, cacheing and
linking for everyone else is compromised. And actually
destroyed if the key is tied to an IP address.

Another temptation is to unify these 'function calls' by saying
you can or should use POST for all of them. Their creators see
GET and POST as effectively equivalent, since you can use
either to convey the function name and arguments and to return
the results. Clearly, in the GET case above, using POST would
also break linking and cacheing.

Some APIs take this to the next stage and suggest you POST an
entire XML function call (XML-RPC- or SOAP-style) to their
service URL. If the 'call' just returns a resource, that
resource is again neither linkable nor cacheable.

This orphaning of resources is another consequence of
function-call thinking: instead of giving all the resources
their own URL, function-call APIs naturally drift into
internal ids that are passed as arguments to the function
call.

In the Web, the various parts of a URL are supposed to be
combined by the web server to identify a single GETable
resource. However, once in function-call land, there may be
many of these internal data-identifying ids passed in as
'arguments' to the 'function'.

This is an aspect of the inversion between function calls and
resource identification: service interfaces naturally publish
function calls and hide data, where the Web publishes data and
hides the mechanisms that animate them.

It's not just about syntactic sugar or arbitrary aesthetics:
function-style URLs are one step away from Web-busting
data-hiding.

Finally, some APIs unify the HTTP method the other way: by
actually allowing GET operations that change server state.

Seeing them as function calls not only makes their creators
indifferent to the unique qualities of idempotent calls (which
break things when POST is used), but equally indifferent to the
converse (which break things when GET is used).

This isn't just a purist objection: links should be followable
by programs, engines, bots and people without fear of
side-effects. It's a basic, fundamental expectation that is
weaved into every strand of the Web. At the very least,
allowing a link that causes side-effects to be constructed and
used via GET is muddying the waters and creating unnecessary
confusion. Someone at some point is going to be tripped up by
this particular abuse.

STREST Breaks the POSTable Web

Now, consider those APIs that allow updates or state-changing
operations as well as data fetching ones - for example, tag
this URL, upload this photo. Even when these state-changing
function calls correctly use POST, there are still a couple of
practical costs to casting these operations as function calls -
specifically scalability and interoperability.

First, scalability: the function call is a bottleneck over those
captive data items. All calls that change internal data have to
go through the same host/port/path combination.

Load-balancing and locking then has to be applied by any one of
a number of ad hoc heuristics. For example, load balancing
could introspect the application ids in the function arguments
to split the incoming calls in some optimal way over the data
they refer to. More arbitrary load balancing implies
independent, asynchronous locking of data affected by multiple
parallel calls.

Functions are expensive and don't proliferate, but real
Web URLs are cheap - and do. If you can POST to real,
fetchable resources, then the handling of that POST can follow
those resources around. And if a given resource just handles
one POST event at a time, it (or the data on which it is
based) doesn't need locking.

The behaviour that responds to a POST on a given type of
resource can be replicated around the world: the ultimate load
balancing and application distribution... And of course, the
definition of that shared behaviour can be distributed around
the world using GET! The Web doesn't need centralised, closed,
singleton, bottleneck services.

While read-only operations can be scaled by cacheing, write
operations only scale by parallelising them. The inherent
parallelisability of declarative architectures such as the Web
is often enough of an argument in their favour without even
considering their simplicity, programmability and power.

Second, interoperability: the only way to interoperate is to
have code written to each service interface specification that
imports and exports data and choreographs (orchestrates?) a
number of threads or workflows and their function calls across
these services. The workflow may even be more-or-less dictated
by the services. This code is tied intimately to the set of
function calls of the specific services being used.

Again, there are many APIs with few implementations; usually
one implementation per API. If the clients have to be built
for each set of service APIs, you don't get general-purpose
clients like browsers; you probably won't get to choose your
client since the cost of these tailored applications is too
high and the market too small. And you won't be able to switch
transparently between services when there's only one service
implementation per API.

Now compare with the Web. There is nothing more 'interoperable'
than bumping into a Web page, finding a form to fill in,
submitting it and getting a result. No discovery services or
interface specifications are needed. You just follow a link you
discovered, look at what's there (the 'interface'), POST, then
see what happened. It's up to the resource how or whether it
changes - whether it provides a simple edit interface or a
more complex domain interaction. It may spontaneously change
itself from other POSTs or from other event sources.

In contrast to the many service APIs describing few or
singleton implementations, the Web has few types and schemas
describing many resources. In the Web World of interaction,
there is a stronger tendency to standardise what you see - both
on GETable and on POSTable resources.

HTML forms and XForms are the well-known document-oriented
standards, for example, that actually dictate the 'schema' for
POSTing. In Web 2.0, the XML from a Web API could
imply the POST that would change it, by convention or by
standardisation (as exemplified by the Atom Publishing
Protocol).

Interoperability is baked in to the Web and the Web Way of
doing things. Of course, interoperability at the HTTP level
doesn't imply interoperability at the level above that uses it.
However, in the Web, this level is invariably standardised
(or settled by convention) in data formats and schemas. If, on
the other hand, HTTP is used to convey function calls at this
level, each such interface is defined by one provider for their
particular case.

A rare counter-example to this (whose rarity proves the rule)
is the weblogUpdates.ping XML-RPC function for telling a blog
tracker that a blog has been updated. This is implemented by
nearly all blog trackers. It isn't actually a function call
in the generally accepted sense, however: it's a notification.
And you need to discover the URL by reading the documentation,
since it is not self-describing.

Of course, it would be better implemented by allowing a POST of
the same information as in the weblogUpdates.ping function
call to an 'updatedblogs.xml' resource. That way, a GET of this
updatedblogs.xml resource would allow the GETter to infer the
ability to do the ping POST, after which another GET would
confirm the addition.

In other words, if it looks like a duck and quacks like a duck,
you can try submitting an 'eat this bread' POST, and it will
probably eat it. If it looks like Atom Publishing Protocol you
can probably try to submit something to the list.

There are various conventions to POST: search forms, comment
submission forms, etc., which boost interoperability by simply
doing what you'd expect them to do.

This blog, whose code and pages were hand-crafted in vim, still
gets successfully spammed even without publishing a WSDL!

Of course, there will be exceptions, where you do need to know
what a specific resource will accept and how it may react, but
even here the resource itself to which you are POSTing can be
filled with information about what you or your code can do.

REST, not STREST

Function calls may be OK for now with small-scale,
early-adopter work, but there is a danger that the
Service-Trampled style of HTTP abuse may get entrenched and
propagated. This will be to our detriment later on when we are
building a much bigger data Web, one that needs linking and
cacheing to work, that needs to scale and to interoperate and
that should be working with the Web's architecture, not
against it.

If the Service-Trampled REST function-call pattern is
propagated, it won't be Web 2.0, it'll be 'Web' Services. And
it won't work. A World Wide Web of Functions will never
happen; the World Wide Web of Resources already covers the
globe.

The key thing to understand is that the value of the Web
as a whole increases each time a new resource is made available
to it. The systems that make use of that network effect gain in
value as the Web gains in value, leaving behind those systems
that remain isolated in a closed application world. Therefore,
an architectural style that places emphasis on the
identification and creation of resources, rather than invisible
session state, is more appropriate for the Web.

.. and more appropriate for Web 2.0! Unfortunately it seems not
to be the Web 2.0 Way, as yet.

It'd be a shame for Web 2.0 to become detached from the
linkable, bookmarkable, indexable, cacheable, parallelisable
and interoperable Web 1.0 that we've all built.

Duncan, even today many "web (form) developers" don't understand the conceptual difference between GET and POST (despite their names being a useful reminder) and treat them merely as a mechanism to switch between using the Query String (also usefully named) and Body to pass name/value pairs.

On top of that, many see Services made available over open standard transports (be that HTTP+XML or SOAP) as merely a user interface where the user is another piece of software.

Whether RESTifarian or MESTian, I fear you have highlighted a very likely eventuality in Web 2.0. *sigh*

Great post, Duncan! This is much more concise and helpful then the previous non-sense about HI-REST and LO-REST. I really hope people take this into consideration.

There's no need to get all religious about REST, just to adhere to the basic principles. I don't see why using only GET and POST less RESTful than using all the other HTTP methods. IMHO, the main benefit (and defining characteristic) of RESTful systems is the use of URI's to allow fine-grained access to particular pieces of information, no matter how small.

Isn't 'accidentally RESTful' what I started this article with, though, before launching into all my objections? And doesn't your linked article from a year ago say the same basic point as this one: that the accident of RESTfulness is a fragile thing within the SOA mindset?

Although these are old, well-trodden arguments, I'm restating them with a Web 2.0 twist and a call-to-arms to protect the nascent Open Data Web.

These STREST APIs are getting out of control - just count how they outnumber the REST ones!

The problem is though STREST = REST, i.e. accidentally RESTful is still RESTful. There's absolutely nothing unRESTful - at least from a URI & GET POV - about the services you're concerned about. Perhaps they'll have trouble in the future, but perhaps not.

It's good to call out the issues of course, but your "call to arms" mischaracterizes the problem IMO.

OK, if we're just considering the function calls that query or fetch data:

Any API that requires an auth key as one of the 'arguments' breaks cacheability and linkability (why can't anyone just GET the XML, just like they GET the HTML? Why limit access just because it's an 'API'?). If access restriction is really needed, using HTTP auth would at least allow a group of authorized users to share the same URL. If anyone knows why the API designers do this, please let me know - I can only imagine it comes from some misguided attempt to restrict access to XML data - some or all of which is probably totally unrestricted anyway on the HTML Web!

Any API that has 'id' arguments to refer to 'internal' data entities has probably adopted Service-Oriented thinking, and considers that data a private matter. If you can construct a GET call to 'export' it to some readable format, they think they're doing you a favour. So don't expect standard HTTP mechanisms to be used: it'll be marked 'no-cache'! You have to keep calling the function if you want to keep getting the data - that's the way services and functions work, right?

Update Another thing I forgot to put in here: while you can see your data through an accidentally RESTful GET function call, don't expect the data returned to have more of these function call URLs included within it as 'links'!! Data doesn't call functions!! Bang goes REST's fourth pillar: 'Hypertext as the engine of application state'...

Update 2 It occurs to me also, that some proxy caches treat anything with a query string on its URL as uncacheable. Which is wrong, but it may be common. This is another reason why auth on the query string is a bad idea, even in otherwise true-REST protocols which allow publishing data in a dataset determined by the auth string - for example, in S3.

June 5, 2006 23:37

From
Skarl

This is partly the fault of web-training books and courses. Until I started reading about REST, I'd never realized POST had any meaning beyond 'send a message to the server' - it had never been described in a resource-oriented way as the complement of GET on the same resource.

December 1, 2006 20:58

From
Peter Schut

REST works brilliantly for relatively simple applications. Fortunately, almost all applications are simple, in that they refer to discrete resources (books, or pictures, or complete widgets of one sort or another).

However, REST doesn't address more complicated applications such as delivering customized maps over the web. Caching is largely meaningless in this world, because every user's maps look quite different from those of other users. Discrete resources don't really exist as such, and service behavior varies based on dozens of parameters.

For these reasons the REST paradigm is not completely applicable. This is where interoperability ends up depending on SOAs based on international standards, like those promoted by the Open Geospatial Consortium.

Don't get me wrong, I love REST - but it's not a silver bullet, and there are some places it just doesn't fit.

REST doesn't care if you have one, ten or a million resource consumers. So if that one resource is for that one user, REST is happy. And you get a distribution model that then scales to millions. Discrete resources do exist even when they're tailored to a single user. Having very finely-specified resources dependent on 'dozens of parameters' is still a task REST can handle. At least that one customer gets the benefits of having their local cache, so even there, cacheing has very real 'meaning', to use your word.

REST is completely applicable to all tasks, in the same way I can code a complex business application in assembler; you can do anything with anything in computing! It comes down, of course, to the trade-offs and expressiveness of the language or model.

I argue that REST - and declarative programming - are simpler and more powerful than all the other alternatives. And you get efficiency and interoperability as happy by-products of an expressive and flexible architecture. REST and declarative approaches generally are more silver and more bullet-shaped than the imperative competition. =0)

It's very disappointing to read in Wikipedia that you have moved from REST to WS. Hopefully a useful set of 'international standard' data schemas can be salvaged after this move, for those of us in the REST camp.

I'd be interested in taking on the use-case you believe most exposes the weaknesses of REST.

"I argue that REST - and declarative programming - are simpler and more powerful than all the other alternatives. "

This type of dogmatic, single-solution ideology turns people, like myself, off to listening to your ideas. Besides being an open-minded programming manager, I teach a martial art. What I've learned over the years is that when someone tells you their way is the only way, you might as well wave goodbye and wish them luck, because they will not be open to "better ways" when they come along; and believe me, in the programing world, they ALWAYS come along.

I recommend tempering your zeal with a bit of humility by realizing that there are no "perfect solutions" to all situations.

• Thanks

February 21, 2007 15:58

From
Ola Berg

URI opacity doesn't include query strings.

March 26, 2007 14:17

From
Tom Anderson

I thought you meant STREST (Streaming REST). Something different altogether.

What number do you get if you increment 4? ( required; to prove you are a worthy correspondent )

By submitting a comment, you agree to its being published under the same copyright conditions as the site itself. Copyright in comments belongs to the submitter. The owner of the site disclaims any responsibility for the content of comments. Comments may be deleted at any time for any reason.