I am curious on what is the preferred way to decouple a core domain entity from the entity served by a REST layer.
I saw on this enlightening Spring REST tutorial http://spring.io/guides/tutorials/rest/1/ that it's a good thing not to expose the core domain model directly in the REST layer as it should evolve independently of the core domain model.
The core service is handling and producing events. These events are seen as the communication ports of the application. The core service does not see any REST domain entity. And the REST controller does not see any core domain entity.
To make things simpler, let's consider the example of only one entity, the Order entity.
The tutorial shows how an Order REST domain class is passed by a REST request to a controller. In turn the controller creates an OrderDetails entity passed to an Order handling event to create a CreateOrderEvent event, which is then passed to a service which returns another OrderCreatedEvent event. The controller finally creates a REST domain Order entity from the returned event, and sends it in the response.
We can see that for this one entity, there is one class for core domain entity, one class for the REST domain entity, and one class for the event payload entity.
Also, we can see that the events, sitting in the application core, extend on some base events which remind strongly of the HTTP methods. It is a bit surprising to see this REST like stuff seeping into the application core, when what we are trying to do in the first place, is to decouple the application core from the REST layer.
Any thought on this design or an some alternate design ? Are there any preferred way of achieving this decoupling ?
Thanks for any suggestion.
Kind Regards,
Stephane
One additional question I now have...
Should I go for an entity NotFoundException exception or for a notFoundEntity event member in the event, on a REST domain decoupled from the data domain ?
The event sent back to the controller can carry a notFoundEntity member state which can be used in the controller.
Here is the event notFoundEntity logic:
protected boolean notFoundEntity = false;
public boolean isNotFoundEntity() {
return notFoundEntity;
}
public static OneAdminEvent notFound(Long id) {
OneAdminEvent oneAdmiEvent = new OneAdminEvent(id);
oneAdmiEvent.notFoundEntity = true;
return oneAdmiEvent;
}
The service updates the event member state depending on the entity having been found or not:
Admin admin = adminRepository.findOne(deleteAdminEvent.getId());
if (admin == null) {
return AdminDeletedEvent.notFound(deleteAdminEvent.getId());
In the controller, a call to checks for the entity having been found or not:
if (adminDeletedEvent.isNotFoundEntity()) {
}
This is in line with the decoupling design.
But, I'm not sure the decoupling event should carry this information. This information can be seen as an exception, a business custom exception.
Also, using an exception makes it possible to specify a rollback attribute in the transactional annotation:
@Transactional(rollbackFor = NotFoundException.class)
With an exception, the only not found entity logic left is on the service, the event does not contain any.
The service now looks like:
Admin admin = adminRepository.findOne(deleteAdminEvent.getId());
if (admin == null) {
throw new NotFoundException("No admin was found with the id " + deleteAdminEvent.getId());
What rule of thumb to use to decide when to use a member state in the event and when to use a business custom exception ?