RESTful APIs, the big lie

Why you might benefit from letting this popular paradigm rest in peace.

RESTful API, rest in peace

Important update

I have added a sequel describing JSON-Pure APIs best practice in detail. But do please read this first.

RESTful APIs are awesome, right?

If you have read an internet developer resume or job posting in the past 10 years, then you might be forgiven if you think that RESTful APIs are gifts bestowed from the heavens by The One True Web Developer Deity. RESTful APIs are everywhere. Even the marketing folks are pushing them in sales material intended for CEOs and Human Resources-type folks.

So how good of an idea are RESTful APIs really? Before we answer that, let’s look at where REST came from, and define RESTful APIs.

Where did REST originate?

REST became popular when it was detailed and promoted by Roy Fielding as part of his doctoral dissertation entitled Architectural Styles and the Design of Network-based Software Architectures in the year 2000. Roy is well known for his contributions to development of the web, especially the HTTP specification.

What are RESTful APIs?

REST is Representational State Transfer, an architectural style intended for building scalable web services. Roy advocated using the request methods he helped define in the HTTP standards to impart meaning to HTTP requests.

Thus the following HTTP requests all have different meanings when using REST:

  • GET /object/list
  • POST /object/list
  • PUT /object/list

There are only a few HTTP request methods. The full list is CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT, and TRACE. You may be forgiven if you’ve never heard of a few of these, as some are almost never supported by client or server software.

Roy also advocated that HTTP response codes he helped define be used to communicate the meaning of the response. There are ~38 HTTP response codes. Below is a complete list. I’ve shortened a few titles in the interest of space:

Method Method
200 OK 201 Created
202 Accepted 203 Non-Authoritative Info
204 No content 205 Reset content
206 Partial content  
300 Multiple choice 301 Moved permanently
302 Found 303 See other
304 Not modified 306 (unused)
307 Temporary redirect  
400 Bad request 401 Unauthorized
402 Payment required 403 Forbidden
404 Not found 405 Method not allowed
406 Not acceptable 407 Proxy auth required
408 Timeout 409 Conflict
410 Gone 411 Length required
412 Preconditions failed 413 Request entity too large
414 Requested URI too long 415 Unsupported media
416 Bad request range 417 Expectation failed
500 Server error 501 Not implemented
502 Bad gateway 503 Service unavailable
504 Gateway timeout 505 Bad HTTP version

The meaning of such an API transaction over HTTP is therefore at the minimum the result of

  • the HTTP request method verb, e.g GET
  • the request address, e.g. /object/list
  • the request payload, e.g. form fields
  • the response code, e.g. 200 OK, and
  • the response payload, e.g. the JSON data.

Many have embraced this paradigm when providing a web service over HTTP, and this is what we refer to here as a RESTful API.

A RESTful API transaction can be more complex than shown above for various reasons, some of which we will discuss below. However, we will ignore the complicating factors associated with network transport and caching since these issues are universal to all communication channels.

RESTful APIs are actually pretty awful

REST is a great mechanism for many things such as content delivery, and it has served us well for two decades. But it’s time to break the silence and admit that the RESTful API concept is probably one of the worst ideas ever widely adopted in web software. Roy is probably a great guy and he certainly had a lot of great ideas. However, I don’t believe that RESTful APIs was one of them.

We will soon review a better way to build internet APIs. But before we can fully appreciate that solution, we must first understand the 5 primary problems with RESTful APIs that make them expensive, tedious, and error-prone. Let’s get started!

Problem #1: There is little agreement on what a RESTful API is

Ever notice how nobody calls their API “RESTpure”? Instead they call it “RESTful” or “RESTish”. That’s because nobody can agree on what all the methods, payloads, and response codes really mean.

Consider, for example, when we might use the 200 OK response code. Should we use it to indicate the successful update of a record, or should we use 201 Created? It seems we really should use a code like 250 Updated but that code doesn’t exist. And can anyone out there explained to me what 417 Expectation failed really means? I mean besides Roy?

The vocabulary of HTTP methods and response codes is too vague and incomplete to get agreement on meanings. No governing body - at least to my knowledge - has convened to set things straight. What one company defines as the meaning of 200 OK is bound to vary in subtle and annoying ways from 200 OK from another company. Which means a RESTful pattern isn’t as predictable as we might like.

If this were the only problem, I’d probably be writing RESTful APIs today. But the problems keep coming…

Problem #2: The REST vocabulary is not fully supported

Even if we could agree on the meaning of the vocabulary of REST, we run into another practical problem: most client and server applications don’t support all verbs or response codes for the HTTP protocol. For example, most web browsers have limited support for PUT or DELETE. And many server applications often don’t properly support these methods either.

So how do we work around these application limitations? One common method developers use with browsers is to embed the intended verb into a browser form. Which means that the REST request now includes:

  • an HTTP request method, e.g. POST
  • a request address, e.g. /object/list
  • a what-we-actually-intended-to-use request method embedded in the request payload, e.g. DELETE
  • and a request payload itself, e.g. form field data.

Response codes aren’t handled much better. Different web browsers (and servers) often interpret response codes very differently. For example, if a 307 Temporary redirect code is encountered, one browser might allow the client JavaScript to consider the response and cancel it before acting upon it. Another browser might not allow the client JavaScript to consider the response code at all. The only truly reliable response codes across all software are 200 OK and 500 Internal server error. After that, support varies from pretty good to abysmal. Because of this, we often see what-we-actually-intended-to-use response codes embedded in the response payload too.

Of course, even if we could get everyone to agree on what REST is, and magically fix all the not-ready-for-REST software connected to the internet, we’d still have another problem: the REST vocabulary.

Problem #3: The REST vocabulary is not rich enough for APIs

The REST vocabulary of methods and response codes is simply too limited to effectively communicate the wide variety of requests and responses required across all applications. Imagine we create an application where we want to send a “render complete” response back to an HTTP client. But we can’t do that using an HTTP response code, because (a) one doesn’t exist and (b) HTTP is not extensible. Bummer. I guess we are back to embedding what-we-actually-intended-to-use into the response payload.

There’s another problem: we don’t have one vocabulary, we have three. HTTP response codes are numbers (200, 201, 202, etc) that don’t directly correlate with the HTTP request methods (GET, POST, etc). And our payload is typically in JSON. Executing a REST transaction is like sending a package addressed in Swahili, with English content, and getting delivery confirmation by message drums. This complexity is a great source of confusion and errors. Which brings us to the next problem: debugging.

Problem #4: RESTful APIs are very hard to debug

If you’ve ever worked with a RESTful API, you know they are almost impossible to debug. That’s because we have to look at 7 different locations to piece together what’s happening in a complete transaction:

  • The HTTP request method, e.g. POST
  • The request address, e.g. /object/list
  • The what-we-actually-indended-to-use request method embedded in the request payload, e.g. DELETE
  • The “real message” in the request payload, e.g. form data.
  • The response code, e.g. 200 OK
  • The what-we-actually-indended-to-use response code embedded in the response payload, e.g. 206 Partial content.
  • The “real message” in the response payload

Not only do we have two very limited vocabularies that no one agrees upon or fully supports, but now we get to look in 7 different places to try to fully understand and debug a transaction. The only thing that could make this worse is if REST were completely tied to one protocol and not applicable for any other communication channel. That, of course, is our very next problem.

Problem #5: RESTful APIs are usually tied to HTTP

RESTful APIs break one of the fundamental laws about good communications: the message content should be independent of the transmission channel. Mixing of the two is a time-honored way to confuse our audience.

The typical intermingling the HTTP protocol of with the meaning of the transactions makes RESTful APIs completely non-portable. Moving a RESTful API from HTTP to some other transmission method requires disentangling and restructuring information from 7 different locations we use to encode the full meaning of RESTful the transactions.

Happily there is a much better solution that avoids or mitigates almost all the problems with RESTful APIs. We will refer to this solution here as JSON-Pure APIs.

The way forward: JSON-Pure APIs

JSON-Pure APIs fix most of the problem we’ve just discussed.

  • They use just one transmission method to send a request - typically POST for HTTP or a send for WebSockets.
  • They completely separate the request content from the transmission mechanism. All errors, warnings, and data are placed in the JSON request payload.
  • They use only one response code to confirm proper receipt of a message - typically 200 OK for HTTP.
  • They completely separate the response content from the transmission mechanism. All errors, warnings, and data are placed in the JSON response payload.
  • They are easy to debug since transaction information is found in easy-to-read JSON inside the payloads using a single, domain specific vocabulary.
  • They can easily be moved or shared between transmission channels such as HTTP/S, WebSockets, XMPP, telnet, SFTP, SCP, or SSH.

JSON-Pure APIs came about because web developers found that RESTful APIs are not very browser or developer friendly. The separation of message and transmission channel results in an API that is usually faster, and almost always more reliable, easier to use, easier to port, and easier to debug. Today, if you use the Twitter API, for example, masochists can choose the RESTful API. The rest of us can use the JSON-Pure API (they call it the “Web API”).

I’ve been asked numerous times over the last decade to use a RESTful API instead of JSON-Pure. The last time I almost had to support a RESTful API was in 2011. Thankfully, the server team agreed to provide an alternate JSON-Pure API along with the RESTful variant by simply stuffing their HTTP methods and response codes into the JSON. After a few months, everyone I knew who used the API had switched to the JSON-Pure version. It was just that much better.

The future of JSON-Pure APIs

UPDATE: I have added a sequel describing JSON-Pure APIs best practice in detail. Certainly, the recommendations aren’t optimal for all situations, but they do result in a the type of API I frequently need for use with responsive Single Page Web Applications. As always, your mileage may vary. But if your use case is like mine, you might just want to make your next API “RESTless” and “go Pure”.

Cheers, Mike

Written on August 10, 2015