REST, PUT and command endpoints

Aug 17, 2015 20:30 · 338 words · 2 minutes read rest CRUD

Nearly all modern web APIs are REST. But lets not do PUT.

REST Methods

The following standard HTTP methods are used with REST:

  • GET - List the URIs and perhaps other details of the collection’s members.
  • PUT - Replace the entire collection with another collection.
  • POST - Create a new entry in the collection. The new entry’s URI is assigned automatically and is usually returned by the operation.
  • DELETE - Delete the entire collection.

These map neatly to CRUD operations:

  • Create is POST.
  • Read is GET.
  • Update is PUT.
  • Delete is DELETE.

But I find it is naive to just map your CRUD data manipulations directly to REST API calls, especially for PUT.

Shortcomings of CRUD + PUT

  • Manipulating an entire resource via Update does not nicely document why you might have to update a set of attributes in a particular manner. Granted, it would be naive to allow a consumer of your API to manipulate a resource into an invalid state - there must be server side validation. But with any good interface, you need to communicate the why. This why helps by documenting where an API endpoint fits in to the bigger picture and how it should be interacted with.

  • Data manipulation is often controlled by business rules, how to do you encapsulate these business rules into easy to use resources?

  • It does not provide any real abstraction on top of the update CRUD operation.

No PUT and Command Endpoints

So lets not do PUT. Instead all update operations will be on command endpoints.

A simple example:

GET https://example.com/orders/
[
    {
        "id": 1,
        "status": "open",
        "created_at": "2015-01-01 00:00",
        "dispatched_at": null
    }
]

So instead of asking the user to update the order by: curl -X PUT -d status=dispatched https://example.com/orders/1 we provide them with a dedicated command endpoint: curl -X POST https://example.com/orders/1/dispatch. We have now captured the explicit domain event of a feature of our API. This endpoint can be explicitly documented and tested. We have only one true way to “dispatch” an order.

See? Much better!