Connect with us


Don’t Use CRUD Styled APIs, Consider Intent-Based Rest APIs

This may come as a shock to you, but even though CRUD APIs work great in a lot of use-cases, it doesn’t work so well in all of them.

A Quick Refresher on REST and CRUD

REST APIs have become an industry-standard in recent years, seemingly taking over RPC and SOAP APIs in terms of popularity.

Coined by Roy Fielding in his dissertation in 2000, the term REST or RESTful stands for Representational State Transfer, and is a design paradigm for building APIs that has several core constraints:

  1. Client-Server: Both the client and the server act independently.
  2. Stateless: The server does not record the client’s state.
  3. Cacheable: The server marks data as cacheable or not.
  4. Uniform Interface: The client and server behave against a uniform interface, or predictably.
  5. Layered System: The application is abstracted away from all layers between the client and server.

Oftentimes, REST APIs are built to mimic a CRUD-like interface, and this stems from the fact that the HTTP standard methods are structured very similarly to the CRUD interface, and REST APIs deal in resources that can be manipulated by said interface.

Extrapolating from this, the CRUD life-cycle of a REST resource is thus: You create a resource, maybe you want to update it occasionally. Down the track, you read the resource, and maybe you decide to delete it.

HTTP Method | CRUD Operation
POST        | Create Resource
PUT         | Update / Set Resource
GET         | Retrieve Resource
DELETE      | Delete Resource

My Main Concern With CRUD

This article isn’t a CRUD slander article, I promise. It has its place in the world (in most systems, truthfully), and personally, I believe it’s really handy in a majority of cases.

When a domain or problem set starts to spiral outwards in terms of complexity, however, I believe CRUD starts to show some of its weak points.

Anyway, let’s create an example we can use for the rest (heh) of this article, it’s not a very complex design, but it should serve the purpose of demonstration.

The Order Model

Here we have a simple model for some kind of product shipping domain.

The entity here is the order and it encapsulates an active orders state, and has several value objects within it to help explain that state.

CRUD requires a very coarse-grained design

It’s true, and that’s fine for a lot of cases, especially regarding smaller domains or models. Many resources contain sub-resources or fields within them that are tied to certain pieces of domain logic.

In the example above, if you wanted to make changes to the orders CurrentLocation, there may be three reasons why:

  1. The order has gone from pending to in progress, and now has an actual CurrentLocation
  2. The order which was in progress has moved
  3. The order which was in progress has moved to its Destination

Let’s say you were given an Order that was in progress, and its CurrentLocation was “Arizona”. Its destination was “Mexico”.

In a normal CRUD like operation, to make a change to the Order’s CurrentLocation to deliver the Order, you might do something like this:

Don’t Use CRUD Styled APIs, Consider Intent-Based Rest APIs

An Update Request for an Order Entity

This is coarse-grained as it takes the entire object as the payload, which forces the user to have knowledge of how the business logic works in order to create a correct call (i.e. if CurrentLocation == Destination, then the status should be Delivered).

This is a request tailored to the CRUD interface, as opposed to being tailored for the problem at hand.

Enter: An Intent or Action based REST API

By understanding that a user will interact with your API to perform specific actions or with a specific intent in mind, it is easy to tailor the models of the request to these intents to alleviate the burden of knowledge from the end-user and shift it into the system’s responsibility.

This strays away from some of the conventional aspects of REST and into almost an RPC-style area, as the API allows actions on verb-based resources or intents/actions as opposed to traditional nouns.

In the example above we saw some cons in the CRUD styled request, so let’s compare it to a possible intent-based variant:

Don’t Use CRUD Styled APIs, Consider Intent-Based Rest APIs

A Request to the Intent Resource to Deliver an Order

Pretty simple, eh? Well, we’re dealing with a very simplified domain. Regardless, this requires the user to have much less knowledge of the domain and makes it impossible for the user to create requests that would leave the data in a bad state.

By POSTing to this resource, we’re acknowledging that the user wants to set the given Orders state to delivered. So, let’s set it’s CurrentLocation to the Destination, and while we’re at it, let’s change its Status to delivered.

Through this, we fulfill the user’s intent and perform the required business logic within our system, without requiring the user to understand how the fields should wire up together.

As mentioned, this is a very simplified example, which is why it may seem a bit plain or simple, however, GitHub actually does something similar with its merges, and a few other places in its API. It uses the resource merges and accepts a POST request with a required few fields, however, it ends up returning a “201 created” for the commit resource. The merges resource doesn’t map to a physical entity, but instead an intent. Neat!


This may come as a shock to you, but even though CRUD APIs work great in a lot of use-cases, it doesn’t work so well in all of them. Intent APIs exist as a way to reify the user intent as an API model, pulling away domain logic from the request or chain of requests, and into the handler for that intent resource, nice and safe away from the poor client.

ThoughtWorks has a brilliant article on this topic which goes into much greater detail. Definitely check it out!

Full Article: Dominic C @ Better Programming