I've had the same problem and "solved" it by modelling REST resources differently, e.g.:
/users/1 (contains basic user attributes)
/users/1/email
/users/1/activation
/users/1/address
So I've basically split the larger, complex resource into several smaller ones. Each of these contain somewhat cohesive group of attributes of the original resource which is expected to be processed together.
Each operation on these resources is atomic, even though it may be implemented using several service methods - at least in Spring/Java EE it's not a problem to create larger transaction from several methods which were originally intended to have their own transaction (using REQUIRED transaction propagation). You often still need to do extra validation for this special resource, but it's still quite manageable since the attributes are (supposed to be) cohesive.
This is also good for HATEOAS approach, because your more fine-grained resources convey more information on what you can do with them (instead of having this logic on both client and server because it can't be easily represented in resources).
It's not perfect of course - if UIs is not modelled with these resources in mind (especially data-oriented UIs), it can create some problems - e.g. UI presents big form of all attributes of given resources (and its subresources) and allows you to edit them all and save them at once - this creates illusion of atomicity even though client must call several resource operations (which are themselves atomic but the whole sequence is not atomic).
Also, this split of resources is sometimes not easy or obvious. I do this mainly on resources with complex behaviors/life cycles to manage its complexity.
This is a very broad question but I will try to give you an answer.
...there is some ambiguity with regard to the use of domain models and application services
There is no ambiguity if you design well your bounded contexts, the domain models and the relationships between them.
However, what happens if there are multiple database hits that depend on business logic?
In DDD
, all the operations go through the Aggregate root
(AR
). The application services
load the ARs
from the persistence, send commands to them, then persist those ARs
back. ARs
don't need to hit the database at all. In fact a good designed AR
does not even know that databases exists at all. All they touch/see/smell is their internal state and the immutable arguments that they receive in their command methods. If an AR
needs something from the database then the Application service
pass that thing as argument.
ARs
should be pure, side effects free objects/functions. One reason is that commands applied on them must be retry-able, in case of concurrent modifications.
As an example: ARs
don't send emails, they return a value object
that holds the email data (from, to, subject and body) and the Application service takes that value object and passes it to a infrastructure service that does the actual sending of the email.
For example, I have a domain model "Order" that has a method "IsValid". To determine whether an order is valid, a database read must be performed.
You don't need an isValid
method, as an Order
cannot get into an invalid state anyway because any modifications are done through it's methods. If you are referring to the existence of an Order
then this kind of validation is done by the Application service
: if it does not find the Order
in the persistence then it does not exist, as simple as that. Maybe you are referring to the ShoppingCart
as being valid, not the Order
. What about then? Well, you could try to create an Order
from a ShoppingCart
and if you succeed then a Cart
is ready to be ordered. As the Order
is side effect free, no order will actually be created. Just an example of how you might think in DDD
.
DDD seems like it provides a lot of nice value, but I'm worried about these kinds of issues leading to design "rot".
If you follow the DDD
approach well, your design will never rot. Never.
As a foot note: In the beginning I was a little miss-leaded by the Layered architecture. Don't make the same mistake. Take a look at some newer architectures like CQRS
that fits very well with DDD
.
Best Answer
The main thing to keep in mind is the point of a web api is to adapt your domain for the web; which is to say, to provide the illusion that your resources are really just entries in a document store.
In a sense, a consumer should be able to drive your API using a web aware document editor.
Coarse grained approach
This is a perfectly reasonable approach to take - you tell the API how you want the resource to look, and the API has to figure out how to get there.
Since shopping carts don't typically call for collaboration among multiple editors, you might get by building a new data model for the resource from the snapshot you have been given, then overwriting the existing model.
If you, for whatever reason, instead need to discover finer grain command messages from the diff; yeah, that can be awkward. In a case like this one, it's not too bad -- you can detect change easily enough, and any valid change is likely drawn from a small vocabulary.
It's also worth noting that you don't need to support PUT on any arbitrary representation of the resource, but can instead pick and choose a representation that makes sense (and, hopefully, one where it is easy to identify the correct changes).
Fine grained approach
Any URI you want to use is fine as far as REST is concerned; but conceptually it might be better to think in terms of removing the entity by id, rather than by position in the list.
Could also be done as a PUT.
Yes; I believe you run into a similar situation with an occasionally connected client. Command messages get queued up until the target system becomes available.
Another approach to consider would be to manipulate the history of the resource, rather than the resource itself. Effectively, the history becomes an append only collection of changes.
There are a couple of answers here, based on the idea that you signal that information in the representations.
One answer is that you simply annotate that the order line should not be deleted. The business rules that decide whether an order line can be deleted live on the server, the client just sees that the flag has been set.
You can communicate that information out of band to the clients.
In the fine grained approach, the usual answer is that you use hypermedia controls. Rather than clients sending a message to a pre-determined endpoint, the client is expected to look in the representation and "follow a link". So you can communicate the fact that an order item can't be deleted by removing the delete item link from the representation.
In a course grained approach, I suppose you could try distinguishing the modifiable parts of the resource from the rest, and providing editable representations of only the parts that the client is allowed to edit. There's liable to be some confusion there.