Last time I wrote about the Anemic Domain Model anti-pattern often observed in RESTful Web APIs. The design smell manifests itself in the data resources exposing CRUD behavior via POST, PUT and DELETE methods. This time I won’t go again through all the complications resulting from such design, but rather just start describing a possible solution.
As a long-time proponent of Domain-Driven Design and a follower of its recent advancement – Command-Query Responsibility Segregation – the solution to apply CQRS to cure anemic domain model seemed quite natural to me (and it still seems so). But how exactly CQRS helps designing hypermedia APIs?
In a nutshell the approach is to model operations that change state as resources on their own, not as methods on data resources. CQRS would call such operations commands and the read-only linked data – queries. I will further call them just actions and data respectively. When represented as resources actions can be linked from associated data resources. Furthermore depending on the state of the data and availability of actions according to that state, data resources can decide to either include or exclude particular action links. Now that’s a navigable API!
Let’s see some actions in action. Consider a resource representing the last 3 calendar events of the user. Depending on whether the event isn’t yet in the past the user can either accept or decline it. An already accepted event can be declined and an already declined event can be accepted as long as they still are in the future. Here is a simplistic JSON representation of such a resource:
The structure of the event objects and the format of the links are not worth paying attention to at the moment. The point this example tries to illustrate is that the action resources are linked in the same manner as any other resources and their presence in representations depends on the state of the data resources they are linked from.
But is a label and a URL enough to describe an action? An action might accept additional information, like a textual comment in the case of a negative RSVP, or require some other data in order to be executed. Actions also tend to change the state of resources and thus should be activated via an unsafe method like POST. How to express such details in an API directly without a need of out-of-band knowledge? This will be the topic for the next installment of my hypermedia blog series which hopefully won’t take another month to write.