Viktor
Viktor

Reputation: 507

Implementing DDD relation/child/aggregate with a HTTP API as persistence

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

Answers (1)

nik0x1
nik0x1

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

Related Questions