DDD - Where should third-party API interfaces should be?

7.6k Views Asked by At

If we consider a standard persistence repository, the solution is easy. We put the IStuffRepository in the Domain Layer, and the StuffRepositoryImplementation in the Infrastructure Layer.

But what is the good pattern when we want to wrap a third-party API?

We could apply the same pattern, having an IStuffGateway in the Domain Layer, and a StuffGatewayImplementation in the Infrastructure Layer.

But there is a problem with this approach. When we consider the persistence layer, we have the control about the data we persist. But when we consider the third-party API, we have no control, meaning that we can TRY to have a certain interface signature, but it has to be influenced by what we are wrapping. So if we change the implementation (replacing a third-party by another), interface signature will probably changes, and the domain be altered.

Another approach could be to move the interface outside the domain, and put it in the Infrasture Layer, with it's implementation. This way, the Application Layer is able to use it without problems (and keep the domain intact). But this approach removes important concept from the domain, which seems to be bad from my perspective.

Any opinions of references about this?

2

There are 2 best solutions below

4
On BEST ANSWER

I am in agreement with Constantin here.

You can still keep the concept in your domain but not the IO. The application layer should provide the required domain objects. You could call your anti-corruption layer (IStuffGateway) and get the required object(s) that you then pass in through some call to your domain.

If this is a common task you may want to introduce an application service (IGetStuffAndCallDomainTask) that wraps that bit.

5
On

I always keep my Domain objects (Aggregates) pure, with no side effects. This means that I don't have any dependencies from the Domain to any other layer. The persistence/repository is always in the Infrastructure. The Application layer uses it to persist the Aggregates.

When I use CQRS, I keep only my write/command side (Aggregates) pure. The Readmodels are dependent and optimized to a specific implementation. Latelly I used a lot MongoDB for persistence.

When I don't use CQRS, I keep the whole Aggregate with no dependencies (I have no choice, splitting would be CQRS).

So, all cases, the Domain doesn't do any IO, it has no side effects. This is mainly because I need to be able to safely re-execute a command on the Aggregate in case of concurrent updates.

If however you decide to use an Interface you should use the DIP: the Domain owns the Interface; this means that the domain decides the number and signature of methods.