Articles
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:
- Client-Server: Both the client and the server act independently.
- Stateless: The server does not record the client’s state.
- Cacheable: The server marks data as cacheable or not.
- Uniform Interface: The client and server behave against a uniform interface, or predictably.
- 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:
- The order has gone from
pending
toin progress
, and now has an actualCurrentLocation
- The order which was in
progress
has moved - The order which was
in progress
has moved to itsDestination
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:

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:

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!
Conclusion
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
