Okay, REST is great, Roy Fielding did really a good job in his dissertation, however, most people seems to misunderstand his point.

Is it this bad? Yes, it is and I will explain you why.

REST design tutorial

For this example, we will take OCTO’s “How to design a REST API” article to see how much errors they made. Please note that they are not the only ones that does that, I just needed an example for this article.

Plural, case consistency and others URI rules

Those rules seems pretty common nowadays, you will see them everywhere, even though Fielding’s dissertation never mentioned such rules. By adding those rules, people thinks it make easier for users to use their APIs and to document them, but it mainly means they did not understand HATEOAS. We will come back to this point later.

POST to create, PUT and PATCH to update

We also see this point a lot, it is wrong. Twice.

  • POST, PUT and PATCH are HTTP methods, and REST is protocol independent. Most people use REST with HTTP, but REST could be used with other protocols. Neither those methods nor “HTTP” are mentioned in Fielding’s dissertation. But okay, we will consider REST over HTTP from now on because it is the most common use case.
  • Even in HTTP, this is wrong.

So, what HTTP tells us about those methods? Let’s check RFC 7231: Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content which defines HTTP methods (except PATCH).

POST

For POST it tells us… Well, it is pretty vague, because in fact, POST can be used for pretty much anything, and also to perform a partial update on a resource, in REST case.

  • If you use POST on a collection, it will mean “add a new resource to this collection”.
  • If you use POST on a resource, it will perform an update. How the update is performed depends on the resource semantic, as per RFC. (also, Roy Fielding confirms this point here)

PUT

For PUT, however, the RFC tells us the following:

The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload.

It means 2 things:

  • You can create a new resource with PUT, as long as you provide the full URI for this resource, not the URI of the collection (as opposed to POST)
  • You can also update with PUT, but you must provide a complete resource.

PATCH

Finally, PATCH, is defined in its own RFC, RFC 5789. What interest us is:

The PATCH method requests that a set of changes described in the
request entity be applied to the resource identified by the Request-
URI.

What is important is that you cannot just give a partial resource (or even a complete resource) to PATCH. How those changes must be formatted is, however, not told.

We could use something like:

[
  { "op": "test", "path": "/a/b/c", "value": "foo" },
  { "op": "remove", "path": "/a/b/c" },
  { "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
  { "op": "replace", "path": "/a/b/c", "value": 42 },
  { "op": "move", "from": "/a/b/c", "path": "/a/b/d" },
  { "op": "copy", "from": "/a/b/d", "path": "/a/b/e" }
]

as defined in RFC 6902 with some RFC 6901 JSON pointers. Fortunately, RFC 7396 defined the application/merge-patch+json media type for us that allow us to perform partial updates with PATCH. Unfortunately, not as straightforward as the OCTO’s article says.

Partial answers

In this part, the article make good use of HATOAS (as I said, I will come back to that later), but the article want us to use HTTP 206 status code. What does the RFC say about that ? This time, we will use RFC 7233, more specifically the Content-Range part. OCTO told us that we can use any resource as the Content-Range unit. The RFC tells us to use only byte, or any other unit defined by IANA. The problem is, there is no other unit defined by IANA.

Okay, so let’s just use 206 without Content-Range then? Unfortunately, Content-Range is mandatory with 206.

If a single part is being transferred, the server generating the 206
response MUST generate a Content-Range header field

The fact is 206 status code and Content-Range should only be used to allow to resume a file download, nothing more.

Content negotiation

OCTO’s is right on that point. Sort of.

  • You should indeed allow content negotiation using the Accept header.
  • You should also use the 406 status code if you cannot use any of the accepted media types.
  • However, application/xml and application/json are really bad types for a REST API. You should go for a hypermedia media-type.

Some example of media-types that support hypermedia:

Well, you will probably not use HTML for a REST API, but it is in fact a better choice than raw JSON.

You could say that HTTP already is hypermedia, using Link headers, but as I said, REST was not made to be used solely over HTTP.

The true nature of REST

Okay, so, lots of mistake, but how to REST then?

The REST constraints

REST is based on 5 constraints: Stateless, Cacheable, Uniform Interface, Layered System and Code on demand.

Stateless

This constraint is pretty basic: doing some calls to the API should not affect future, except if said calls update resources. You cannot call /login and expect the server to remember you logged. The server will give you some sort of token, and you will have to send it back to the server every time to say “hey, it’s me”, because the server will just forgot every single calls you made in the past.

Cacheable

Once again, basic: if the client has the data and asks for it, the server should just says “you already have it!”. 304 Not Modified, ETags and conditional requests are your best friends for this constraint.

Uniform Interface

This constraint means that every single endpoint in your API should use the same format as every single other endpoint. It might not be network efficient in some case, but it means a true REST API is really easy to interact with, plus the Cacheable constraint takes care of the network efficiency.

Layered system

A little bit harder, it means your every layer should hide layers below and above. It is used to hide some legacy stuff, for example.

Code on demand

This one is optional. It means that if the client is not able to used some part of your API, your API could provide some snipped of code the client could execute to gain this missing ability. Of course, it means that clients trust the API. And of course, nobody ever implements this features.

HATEOAS

Well, in fact, I already talk to you about HATEOAS in the Content negotiation part.

HATEOAS stands for “Hypermedia As The Engine Of Application State”.

It simply means that the API should always provide links to explore the API, eg: next page, previous page, parent, author of this resource, etc… It is in fact the main reason why every single rules on how URLs should be formated are wrong: nobody should care about the URLs, you should just follow the links.

Also, it means that, if you correctly document your resources, your media types and the relations of your links, you are all fine, you do not need to explain all your urls and what will be the specific body from one URL.

Conclusion

With all those information, think that Roy Fielding did create a really neat architecture, but he failed to make people understand what he meant. So, should we continue to use REST? I do not think so:

  • Either it will not be REST, you lose all the point, maybe go for RPC then?
  • Or it will be REST, and nobody will understand how it works.

Fortunately, some new architectures came out recently that came out to replace REST: GraphQL and Falcor, maybe you should give them a try.

And last, but not least, a nice article from Roy Fielding, if you really want to go for REST: REST APIs must be hypertext-driven
You can also check “RESTful Web APIs”, by Leonard Richardson and Mike Amundsen.