Lately, I’ve been studying the fundamentals of Software Architecture for web applications, and I’m a bit unsure about how the data and presentation layers should interact.
From what I understand, the presentation layer is responsible for operations like validating requests, handling authentication, and so on. Meanwhile, the business logic and query handling should live within services or, in some cases, dedicated queries and commands.
My question is about data serialization and transmission: what’s considered a "clean" approach here?
Should a service or query return a fully prepared DTO containing all the necessary information? Or should it return the raw entity, leaving the presentation layer to handle the mapping?
My main concern is about the potential downsides of each approach:
If the service returns a DTO directly, it could be limiting if another service from a different module needs access to the entity. I assume that services should only interact with other services from different modules (not with repositories or data layers) to avoid tight coupling.
If the service returns the entity, how should the presentation layer handle mapping, especially when the response requires data from other modules? Should the response act as an "aggregate", mapping the necessary fields and fetching additional entities as needed?
Thank you!
1 Answer 1
I think the best advice is "imagine you have two apps that use the same business logic"
Of course the data needed for the presentation layer in each app will differ, but the underlying entities and logic will be the same.
You need to seperate the presentation logic from the business logic. That doesn't always mean no viewmodel DTOs. you can add a backend for front end intermediate layer if you want to put the presentation logic server side for some reason.
But usually it means the presentation logic, the assembly of the viewmodel from the models, happens in the app itself. Not on a backend server.
In regards to your worry:
If the service returns the entity, how should the presentation layer handle mapping, especially when the response requires data from other modules? Should the response act as an "aggregate", mapping the necessary fields and fetching additional entities as needed?
The presentation layer can make several requests, or use cached data to assemble its viewmodel. The "response" should just be entities, or the results of business operations (true/false) etc
-
Thanks for the explanation Ewan. I still have a doubt. Reading your explanation, I suppose in monoliths, where usually multiple modules live within the same application, presentation logic should be placed inside controller (in case of a REST scenario). In this case, if a service returns an entity, I guess I could make an "aggregator" class that assembles the DTO. Do you think that this "aggregator" should interact with other, again, services or directly with the data layer (for example, through a repository)?ikiwq– ikiwq08/24/2025 17:37:34Commented Aug 24 at 17:37
-
It can interact with whatever it needs to? Can you maybe describe your application, what tech stack are you using, archtecture etc?Ewan– Ewan08/24/2025 18:33:45Commented Aug 24 at 18:33
-
1Ok, so in this setup the front end team control the presentation, so they should make two calls, getBooking, which returns a
Booking
entity with a ClientId and (if they want it) a second call to getClient which returns aClient
entity.Ewan– Ewan08/25/2025 13:33:03Commented Aug 25 at 13:33 -
1They will moan that this is slow because they are lazy, but if you think about it, they probably already have the
Client
object and can reuse it. so its actually faster and better design overall. as both endpoints are reusable for many presentations, rather than being coupled to the presentation layer for this particular front end.Ewan– Ewan08/25/2025 13:35:19Commented Aug 25 at 13:35 -
1If they are incapable of writing javascript to do this stuff, then you can add a "backend for front end", intermediate layer which basically just does the same thing, but server sideEwan– Ewan08/25/2025 13:36:49Commented Aug 25 at 13:36