Alexander Zeitler

"CRUD APIs are poor design" - a follow up

Published on Thursday, December 5, 2024

Derek's statement...

The gist of Derek's video, which he published yesterday, is this:

Typical API Design consists of building around database records and Create Read Update Delete. Making nothing more than a UI or HTTP API around a database. But that database schema was driven by business processes. But if those business processes don't live in your system, then trying to evolve your schema can be challenging. Instead of modeling data structure, model business processes and the data behind them.

... and my follow-up

As with most of Derek's videos, I completely agree with him.

Yet, I want to add one or two thoughts.

Back in the days, when I was young, we only had what's called "server side rendering" (SSR) these days.

When HTTP JSON APIs and Single Page Applications took off almost 15 years ago, this seemed to be the promised land - even more so with the advent of Microservices.

And yet here we are today, with failed projects, drowning in either technical debt or complexity - or both.

While a lot of things we've done as developers (and architects) in the past, have been doubted, CRUD still is accepted as the default storage pattern for most applications.

At the other side of the applications, having an HTTP JSON API, also has become the default.

Be it CRUD or HTTP JSON APIs: there has been built a ton of tooling around both of them, often to handle the complexity which these patterns are causing.

But to be honest: I think this is a dead end.

While it is compelling to sell tools, that deal with complexity and other issues caused by CRUD and HTTP JSON APIs, it will never solve the root cause.

The root cause - in my opinion - is trying to solve business problems with the least amount of business understanding and the biggest amount of technology possible. It may sound like an exaggeration, but I've seen it more than often in real world projects.

"So, what's your solution?" one might ask.

I wouldn't call it "solution" but I'm explaining my approach.

In short: less complexity and more explicit code.

What does this mean in practice?

Less complexity

By "less complexity", I mean choosing a boring stack - in my case that's ASP.NET Core MVC.

It's production tested for ages. Especially when building something new - in terms of business model - the more code you create in the beginning, the more effort you have to put in maintenance and changes. And when exploring a new business model, you will have a lot of changes.

You're creating legacy code with no need to do so.

"Will it scale" is the wrong question if you have no customers.

And if you do get more customers, how do you scale in terms of business and features, if nobody knows why this data even exists and who's changing it?

"API first" has been all the rage for years, but from my experience a lot of APIs being built are used only by the product vendor in the SPA frontend itself.

So why not start with a simple sever side rendered UI in the beginning?

Due to lower ceremony (think AuthN/AuthZ, mapping data and whatnot), you can focus on the business processes (yes, that's what earns the money - not the code).

To gather a good understanding of the processes, I would recommend using techniques like Event Storming or Event Modeling (my personal choice).

That way you get an understanding of which data belongs together (coupling/cohesion), hence should exist in the same context or vertical slice.

Building the UI for these slices with minimal effort as described above, you'll notice that data that is - and should be - coupled will be placed closely together in the UI as well.

Which brings us back to APIs: your server side rendered web front end is the first implementation ("representation") of your API - it's just serving HTML instead of JSON.

Now you might tell me: "but its structure is completely different from what my JSON API would be".

Yes, because people are building JSON APIs around entities instead of processes.

Now instead, think about providing a JSON API that looks exactly what your HTML forms or tables (lists, grids) look like - just in JSON.

Hint: You don't need to re-invent the wheel here: Hypermedia has got you covered - give HAL, HAL forms and real REST APIs a chance.

And maybe, maybe out of sudden there's no need for GraphQL any longer, because data that belongs together isn't spread across services/contexts/slices.

Explicit code

Now you might ask another question: "but I have so many different views, how do I get all the entity data together?"

The answer is: don't use one model to rule them all.

Create dedicated models for specific views, because these are only representations of your data.

Which brings us to the next question: "what is my data actually?"

Data doesn't "just" exist - it comes to life by filling forms to meet the needs of business capabilities and processes.

Calling it "filling forms" doesn't do it justice - you're completing a step in a process.

In terms of business, this step has a meaning and most of the time a name already.

Examples are "add item to cart", "book a room", "place order" - you name it.

Now we're closing the loop with Derek's video:

Model the events that have happened, after you completed the steps mentioned above successfully.

You'll end up with "Item added/removed to/from cart", "Room booked", "Order placed".

Store these events instead of the state of a cart, room bookings or orders.

Now you can start asking questions like the business wants it to do:

  • "Which items have been removed from the cart before an order has been placed?"
  • "Which options (beamer, whiteboard etc., room size) have been chosen/unselected before the room booking happened?"

Because business wants to understand which products don't sell and why.

The immutable truth is in your persisted events that will be there forever (if you want it to) and anything else are just different representations of the truth.

Combined with Event Modeling you make it very explicit where your data comes from - properties for some state don't just exist - they're caused by a command and even more important: they're persisted in one or more events - now you are able to point exactly at a diagram or in your code and tell when a property comes to life and when it gets changed - and on top you get the reason for it.

Being able to evolve your code is the only way to keep your business up in the long term. By knowing where your data is caused and modified, you're able to delete or change code (evolve) without being afraid of breaking things for your users when making required changes.

So, in addition to Hypermedia/HAL, you might consider Event Sourcing instead of CRUD.

And that's my thoughts around this topic.

What are your thoughts about
""CRUD APIs are poor design" - a follow up"?
Drop me a line - I'm looking forward to your feedback!
Please be aware that I'm no longer active on social media. I'm just cross posting things over there (it's a bot).
Imprint | Privacy