Let's say I am building a basic REST allowing CRUD operations on some object type A.
I am using clean architecture, so
The definition of A itself sits in the Domain layer. This includes any business logic inherent to it, such as a constrained relation between two fields (e.g age and birthdate)
The high-level logic of the CRUD operations, including any app specific validation, data generation, and generic data access calls, will sit in the Use Case Layer.
Persistent Data Access, REST Frameworks and HTTP-specific logic will sit in the Infrastructure layer, implementing port interfaces defined in the Use Case layer.
Now, I would like to implement the Update Use Case. The format that this use case knows to how to handle is not exactly A
, but a different, similar model that can have missing fields (a user my want to only update some of his object's fields). This is also the model used by my Data Access port interface, as it needs to be the same format the Update Use Case uses.
My question is, how, in this scenario, does my server enforce the application agnostic (domain) business rules? At no point does the update request gets translated through the domain definition of A. My Update Request cannot extend or contain A
in any real manner, since it may contain even just one field of it, or no fields at all.
In my trying to solve this problem on my IRL job, I put the Update Request in the domain layer, including app agnostic rules into that model "by hand". Surely that is the wrong approach, since the Update Request is definitely an application specific format.
Is there a known, recommended way to handle this issue?
What I usually do in these cases is:
A
must have methods/commands to perform the update action, checking all needed business rulesUpdateUseCase
(I describe just the happy path)
Now, I would like to implement the Update Use Case. The format that this use case knows to how to handle is not exactly A, but a different, similar model that can have missing fields (a user my want to only update some of his object's fields).
Let's call it ToChangeA
This is also the model used by my Data Access port interface, as it needs to be the same format the Update Use Case uses.
What's wrong here is that your DataAccessPortInterface should accept only instancies of A
, not directly ToChangeA
.
And you get your updated instance of type A
using the method A.update(ToChangeA)
of the domain layer.
I hope it's clearer now