Home - Programming - REST vs. not-REST.

It's already been a long day, and I'm tired, but this pet peeve of mine has resurfaced, and I just have to say something.

REST stands for REpresentational State Transfer, and as applied to HTTP, it's probably the simplest way to expose your data and business rules through an API. The basics are simple.

1. Every operation occurs on a resource, and the URL describes the location of the resource. A resource can either be thought of as a container (eg. "invoices") or a single item within a container (eg. "invoice/12345789").

2. There are four basic operations that can be performed on a resource, and those are indicated using HTTP verbs:

  • Create = POST. This is applied to container resources.
  • Read = GET. This can be used on a single item or to list the contents of a container.
  • Update = PUT. This is typically applied to a single item in a container, but in some implementations can be applied to a container.
  • Delete = DELETE. This is normally permitted on a single item, since deleting a container would delete all of its contents in one operation.
  • 3. When creating or updating an entry in a container, the data state to apply is passed in the POST/PUT body. Depending on the implementation, there are two ways to treat columns to be cleared during an update:

  • All columns must be included, and ones that are omitted are interpreted as being set to null.
  • Only columns to be updated are included (allowing for much smaller payloads), and omitted columns are not updated. To clear a column, it must be included in the payload with an empty value.
  • For efficiency's sake, the latter approach is more common.

    4. There is NEVER a verb in the URL. The URL is reserved for locating a resource, not specifying what operation to perform. If you put a verb in the URL, it's not longer REST, it's RPC. Period, end of story. So this:

    POST /v1/rest/invoices HTTP/1.1 ...indicates an insert operation on the invoices table, while this: POST /v1/rest/invoices/create HTTP/1.1 ...or even worse, something like this: GET /v1/rest/invoices/12345679/hold HTTP/1.1 ...indicates you don't know what you're doing. It's really that simple. To correct that last example, if you wanted to put the invoice on hold, you'd do a PUT and in the data state you'd set the "held" flag to true. But the URL above is calling a "hold" method, and that makes it a Remote Procedure Call (RPC), which is NOT REST.

    5. Qualifiers to an operation should be passed in the HTTP headers, although it's common to see them passed as parameters in the URL. So you'll often see pagination achieved like so:

    GET /v1/rest/invoices?start=1840&rows=20 HTTP/1.1 That request will return 20 rows starting at row 1840. Or to filter a result set and only return certain columns, you might see something like: GET /v1/rest/invoices?filters=(saleDate,gt,"2017-06-01")and(held,eq,false)&cols=invoiceNum,saleDate,invoiceTotal,associateId HTTP/1.1

    There. Now buy a book on REST best practices and HATEOS, and you're an expert. But please, PLEASE, if you decide to put verbs in the URL, do not advertise your API as "REST-based". It isn't. It's RPC, and you suck.

    Todd Grigsby