REST vs RPC

Verbs are just not that evil
Published on December 2, 2023

Fighting Wizards

How it all started

RPC is as old as time in computer years. It was first described in a paper published in 1983. The premise was simple, developers know how to call procedures, making network calls at the time was really hard, so lets build a bunch of infrastructure code to make network calls look like procedure calls. It was the epitome of abstraction.

In the late 80s, Object Oriented programming came along and we spent a decade trying and failing to make remote objects a thing. In 2000, Fielding's dissertation on architectural styles introduced the world to REST. And ever since then we have been having REST vs RPC debates.

One of the more influential blog posts from the early 2000s had a profound effect on peoples understanding of REST and more specifically the uniform interface constraint. The blog post is no longer hosted by the author, possibly because it had a title that would not be well received today, but a LinkedIn user preserved it for posterity. The essence of the blog post is that REST is all about using a set of standardized verbs to interact with nouns. This was an awesome "101" description of REST but unfortunately people decided to take that guidance a little too literally. And so began the dogma of never putting verbs in the URL.

What is a procedure

A procedure is a mechanism designed to enable code reuse. You wrap the code you want to reuse in a signature that can be parameterized and you immediately become massively more productive. Ideally a procedure is a stateless thing. The reusable code operates on the parameters you pass it and it can optionally return a result. The notion of global state does allow procedures to act on data beyond what was passed in, but that becomes a slippery slope because there is no visibility on the global state that is participating in the behaviour of that procedure.

That brings us back to Object Oriented programming. Object oriented programing forces the developer to make a distinction between values that affect the behaviour of the procedure, or method in OOP terms, and the application state that is being modified. In a procedural approach, you might have:

DepositMoney(account, amount)

whereas, an object-oriented approach might look like:

account.DepositMoney(amount)

The OOP approach makes it very clear that it is the account that is being changed by the amount. With the procedural approach, the developer needs to intuit this information. In more complex procedures and interactions this can get hard.

But why am I talking about object oriented programming?

Resource Oriented HTTP

It is not a coincidence that HTTP methods are called methods and not verbs. Resources are the spiritual equivalent of objects but for a network based system. The major difference between resources and objects is that resources are accessed via their URL instead of via some kind of reference or pointer. However, "Resource Oriented" has the same benefits to the developer as "Object Oriented" in that it makes a clear distinction between the system state that is being manipulated and the parameters of that method doing the manipulation.

In HTTP, you could do this:

POST /accounts/23434/depositMoney
Content-Type: application/json
{
  "amount": 100
}
=>
200 OK

However, many people that will argue that this is "not RESTful". I believe, this is based on the dogmatic conclusion reached from the earlier referenced blog post, and other sources, that URLs should not contain verbs and we should be limited to only use the provided HTTP methods. Common guidance for this situation would be that you should model the account transactions as resources so that the POST method is used to create a transaction.

POST /accounts/23434/transactions
Content-Type: application/json
{
 "type": "deposit"
  "amount": 100
}
=>
201 OK

While the latter design does create the opportunity to enable consumers to query the transactions against the account, it has forced the API designer to expose resources that they may have no scenarios they want to support. I think there is value in an API designer being aware of the opportunity to model the transactions as first class resources, but I also think they should be able to choose the first design option without being told that their design does not conform to resource oriented principles.

There is a perception that the uniform interface dictates that APIs should treat the HTTP methods as if they are mapping to CRUD and that any other verb is violation of that constraint. Unfortunately, that perception is based on an assumption that POST === CREATE. However, that is not how HTTP defines POST. It says POST can be used to create resources. It does not say that is the only thing it can be used for.

POST is a "catch all" method to be used when an operation does not fit into one of the other methods. It says "it might not be safe and it probably is not idempotent", other than that I can't tell you much more about it. HTTP gives an example that POST can be used to create resources, and an intermediary can see that happens when they see a 201 response. The POST method itself does not tell you that something was created, the 201 response does. A POST that returns a 200 is perfectly valid HTTP but it doesn't tell an intermediary a whole lot about what happened.

Verbs are handy for manipulating state

Resource oriented is an approach that allows a developer to be explicit about how they want to interact with state that their client application does not own. The uniform interface constraint of REST is there to make common interactions visible to intermediaries for transparency and simplicity. It does not say that every round interaction must be squeezed into a square hole.

On the other hand, RPC is an ideal way of reusing code that lives on another machine to manipulate state the client owns. Using RPC to build a service that owns state is not the most natural approach because it is not clear what state is being manipulated. Putting a verb in a URL does not suddenly make an API RPC and we should not be telling API designers that they should turn every concept into a resource so that we can pretend that the uniform interface means everything should be CRUD.

As I have been telling people for years, when someone says "that's not RESTful", make sure you ask them what is the cost. Most design choices are a trade off.

An apology

I was driven to write this blog post because this topic has been nagging me for a while and the other day I bumped into a Mastodon toot pointing to an article about the myths of REST. I always go into defensive mode when reading articles with titles like these and right there up front was a discussion that on the surface appeared to be about REST vs RPC. At first glance appeared to be falling into the verbs are evil trap. Idiot me stopped reading and instead tooted a comment about the blog being incorrect. The blog post is far more nuanced than I gave it credit for and it was only when I read it more carefully did I appreciate the precision of the words and the insight it shares. It is a short article with useful information, it is worth your time. I want to apologize to Poornima and say thank you for providing me with a learning moment and motivating me into getting a blog post written on a Saturday morning.