Search code examples
oopinversion-of-controlclean-architecture

What should application layer return? entity or dto?


In clean architecture, I implement restful api as an infrastructure,

the question is: what should the application layer return

1 - entity: this is what chatgpt answer, it say the application layer will return entity, then we will map it into dto in infrastructure layer (controller), but I think public the entity to the controller is not a good practice.

2 - dto: I think we should map the entity to dto in application layer, but incase the function need to serve more than one infrastructure, how should we implement it, for example a create post api which is need to use server sent event to send notif to client

what do you think, what should be the good choice?


Solution

  • tldr: what chatGPT said... (kinda)

    IMO, the important thing with the approach of Clean Architecture is the separation of concerns between layers, and the rule of dependancy which means that the inner layers (high level) know nothing about the outer layers (low level). This is because you don't want to have cascading and unexpected changes around the application.

    enter image description here

    According to the diagram, you can see that the application (Interactor) is returning a Response Model, and the controller is receiving the Response Model.

    I think that the important thing is that the transport (controller) will format the Response Model into a response, and will encode it using the specific mechanism.

    I am not talking about an entity that has methods for Save/Update and such. For me, this is a job for the repository layer, and the entity is a mere DTO with maybe some business policy rules.

    In pure Clean Architecture, you are right, the Response Model shouldn't contain an entity, but IMO, it doesn't matter what you are returning in the response, if the transport simply returns the response model data in the HTTP response body, you are coupling the entity to the transport. When the entity will change, the response will change (unknowingly), and worse, if you will want to change the response to the client, you will change the entity, which absolutely breaks the abstraction. This means that the entity and the application are aware of the http transport layer. (Even though these components don't have the word "HTTP" in them).

    Need to note that this drawing is only a high-level idea about Clean Architecture. For example, I am working with Go (and go-kit like framework) which makes this separation super convenient. The application (domain service) returns an entity, but I have another component which is called "endpoint" that takes the entity and wraps it inside a Response Model (either the entity itself or related data). The transport takes the Response Model and formats it into the HTTP body. If I want to add another transport (for example gRPC), I need only to add another transport that uses the same endpoint, receives the same Response Model, and formats it to the appropriate mechanism.

    If you won't make this separation, these two responses will be coupled.