Reputation: 507
We are doing a REST web API in C#. We have some form of clean/onion architecture with application, domain and infrastructure layers. I would like to inject some DDD ideas into the project so that the domain model actually represent the domain structure.
However, our persistence/infrastructure does not directly access a database using Entity Framework as many examples show. Instead we query other API's and we have repositories for types that I would not consider aggregate roots.
Question 1
Let us say we have an aggregate root model System
that is identifiable. The SystemRepository
queries API 1 via HTTP and can return a System
. The problem I am having is that I want a method GenerateReport()
on System
for generating a Report
for that System
.
A Report
is not an entity and can be constructed by querying API 2. I would like to keep HTTP calls to API 2 in infrastructure layer, other layers should not care about if the data store is HTTP or a database.
I could create an interface IReportService
and implement this in infrastructure, have it injected in the controller and pass it to System.GenerateReport()
, but it is easily misinterpreted as a BLL service. I ideally would not want to see the use of IReportService
in application or domain layer.
What would be a good idea to solve this?
Question 2
The other problem I have is that from my controller endpoint I want to return the Report
. In order to do the DDD way I need to first get the System
which means calls to API 1. But the client already knows the identity of the System
when requesting a Report
so I would like to bypass calls to API 1 and just go to API 2 and get the Report
. Here, I am thinking I would need a cache implementation, am I thinking right?
Upvotes: 0
Views: 64
Reputation: 1357
If I were you, I would try to divide the task into parts, because at the moment you are solving all the problems at once.
For example like this.
Step 1. Define the APIs and don’t think about other aspects at this stage.
Because you specified the REST
tag, for example like this:
/systems/{systemId}
/systems/{systemId}/report
Step 2. Determine the level of entities. It is not entirely clear from the description what the system is and what functionality it carries. For example like this (pseudocode):
interface ISystems {
ISystem system(systemId) {...}
}
interface ISystem {
// operations
ISystemReport report() {...}
}
Step 3. Define middleware layers whose responsibilities include: calling entities and passing them to the API layer, security, caching, etc. Simplified, something like this (pseudocode):
class SystemResource {
ISystems iSystems;
// constructors
@GET(/systems/{systemId})
SystemResponse getSystem(systemId) {
ISystem iSystem = iSystems.system(systemId);
// mapping iSystem to systemResponse and return systemResponse
}
}
class SystemReportResource {
ISystems iSystems;
// constructors
@GET(/systems/{systemId}/report)
SystemReportResponse getSystemReport(systemId) {
ISystemReport iSystemReport = iSystems.system(systemId).report();
// mapping iSystemReport to systemReportResponse and return systemReportResponse
}
}
P.S. As you can see ISystems
, ISystem
, etc. are interfaces. And therefore you can define any implementations (getting information from the DB or something else).
Upvotes: 0