In a now famous blog post, Roy Fielding the inventor of the REST architecture criticized the misuse of the term RESTful. In particular, he made a distinction between RPC and REST interfaces.
My understanding of this is that in an RPC interface all the methods of state transition (including their location and meaning) are known a priori to the client, whereas in a REST interface the client and the server only need to speak a common language (have a shared media type with a priori syntax and semantics) that describes the application state and (location and meaning of) the methods of state transition, and that the actually available methods are discovered by the client at run-time.
I can see this being a non-trivial constraint when the client-server situation is something specialized like say a smart light bulb interfacing with its bridge, but when the client-server relation is that of a web browser and a web server, isn't the above RESTfulness constraint trivially satisfied?
This assumes that the JavaScript possibly delivered by the server is taken as being part of the representation (and hence can e.g. contain hard-coded links as it pleases without breaking RESTfulness). On the other hand, one could also take the view that the combination browser+js is the actual client, and then RESTfulness impose a non-trivial constraint on the design of the JS client. But isn't this view rather construed?
It's a non-trivial constraint on JS code. JS should be thought of as a client rather than a resource representation. It's true that it's both, but only from 2 different points of view. When the JS is wearing it's "resource representation" hat, it's inert and doesn't do anything. When it's wearing it's "REST client" hat, it no longer matters that it came as part of a resource representation.
Hard coded links aren't the only problem: JS code concatenating strings to build links using inside information is a problem too. These violations of REST affect the property of "modifiability". This might not seem like a problem when you consider that the JS code and server implementation are typically developed as part of the same project. The URIs and the client URI-building logic can easily be kept in sync, right? But what if you have multiple apps with their own JS clients that share a single server API implementation? Any change to the URIs, you break lots of clients.
JS code should be bound by the same rules as any other client: the links should come from resources provided by the server, and the semantics should come from the common understanding of the media type.
A Concrete Example
Suppose we have a resource /readinglist/ which is defined as a collection of books, and looks like this:
{
[
{
"id":"GoT",
},
{
"id":"LOTR",
},
{
"id":"IT",
},
...
]
}
The JS code displays the list, and if the user clicks on an item, the JS GETs the corresponding "book" resource, to display more detail:
GET /readinglist/IT
{
"id":"IT",
"author":"Stephen. R. R. King"
}
This is an all-too common pattern in so called "REST" apis. But what's happening here is that the JS must contain logic that says you retrieve a book by appending it's id onto the collection's URL. In other words, the client state is driven by out-of-band information. You could argue that since the JS code itself came from the server as a resource, this isn't really out of band information. But the JS is now acting as a client, and should be analyzed as such.
In contrast, consider this representation of the /readinglist/ resource:
{
[
{
"id":"GoT",
"link:"/books/GoT"
},
{
"id":"LOTR",
"link:"/books/LOTR"
},
{
"id":"IT",
"link:"/books/IT"
},
...
]
}
Now the JS does not have to know how to concatenate URLS. Instead, it must have logic that says you get a book resource by following the "link" URL in the collection's representation. Is this any more or less complicated? It's about the same. The key difference is that with this approach, the client's state is driven by hypermedia, based on the agreed semantics of the media type. Once the media type and it's processing rules have been figured out and standardized, it can be re-used in multiple APIs.