I am building an API Rest with Spring Boot and I would like to clarify a concept about my architecture, to see if the community can help me.
Imagine that in my database I have a table called Person. I am mounting an architecture based on three layer architecture. The general scheme would be as follows:
On the one hand I have the
PersonDao.java, which will be in charge of accessing the database to retrieve the tuples from thePersontable. To do this, it uses a class calledPersonEntity.java, which contains (as attributes) all the columns of the table.PersonDao.javais going to return an object from thePersonModel.javaclass.PersonModel.javais the class that represents thePersonbusiness model.On the other hand, I have the
PersonService.java, which is responsible for carrying out the business logic of my application. This service callsPersonaDao.javato access the information stored in the database.PersonService.javaworks with objects of thePersonModel.javaclass, since this class represents the business objects of my application.PersonService.javawill always return aPersonDto,java.Finally,
PersonController.java. This controller will be the one that exposes the connection interface of the Rest API. He always works with DTO and communicates withPersonService.javathrough DTO as well.
PersonController <-> (PersonDto) <-> PersonService <-> (PersonModel) <-> PersonDao <-> (PersonEntity) <-> DB
The question is: Is it necessary to use the PersonModel.java class so that PersonService.java only works with objects of this class? Or would it be better for PersonService.java to work directly with objects from class PersonEntity.java? If I do it this way it is to maintain the principle of single responsibility, so that each layer only works with objects of its scope.
If the answer is that PersonModel.java is necessary to maintain the principle of single responsibility of each layer. Would something change if JpaRepository were used? If I ask this question it is because in many tutorials and examples I see that when JpaRepository is used, the services work directly with the entities. In this case, shouldn't we create a class that represents the business object for the services?
EDIT: In the answer to this question (Spring Entities should convert to Dto in service?), the architecture that makes sense in my head would be reflected, but surely it is not the most correct thing. The conclusion I come to is that each layer would use its own kind of objects. Copy / paste of the answer:
Typically you have different layers:
- A persistence layer to store data
- Business layer to operate on data
- A presentation layer to expose data
Typically, each layer would use its own kind of objects:
- Persistence Layer: Repositories, Entities
- Business Layer: Services, Domain Objects
- Presentation Layer: Controllers, DTOs
This means each layer would only work with its own objects and never ever pass them to another layer.
Thanks in advance.
From what I understand your question is particularly about the layers and their useage within the
logictier. (Thus thepresentationanddatatiers are not part of the question).About the
PersonModelI am not sure, what you mean with the
PersonModeland what it actually does, but at first sight I can say you normally would not need something like that, which would just add additional code duplication and maintenance overhead sooner or later.About the
PersonDtoThe
DTOs, as the name suggests, are really meant to be for transferring data between the client (presentationlayer) and your API (controller / boundarylayer within thelogic tier) which are used to expose "client friendly" presentation of your domain model, to regulate the over- and under-fetching - somehow (thanks to GraphQL this is now almost no longer a problem). So your business service classes don't need to know or deal with the DTOs at all.Also, as you already mentioned, for the sake of SRP the business or dao classes should not deal with additional data mapping (e.g. Dto <-> Model, Model <-> Entity) in any way. They already fulfill a certain task within the logic tier (cf. boundary layer, service layer).
About the
PersonEntityThis is something that normally represents both the real entity from your problem domain and
datatier (e.g. database table in a RDBMS or document in a NoSQL). So it's pretty commonthat the entity classes are named without a suffix such as
Entity. Just use the plain name for it, e.g.Person,that the entity classes contain additional annotations (e.g. JPA) to make them visible for the
ORM layer(e.g. Hibernate),that the entity classes should not be necessarily anemic and actually contain some additional behavior (probably what you wanted to do with your
PersonModelclass), e.g.Wrapping up
Use case: creation of
PersonentityHinflug (outbound flight)
Note:
<Validation>can also be done within the Controller manually but usually Bean Validation API is used to automate this process in the backgroud. The good thing is you can use the Bean Validation API to validate both your DTOs and the Entities (e.g. with Hibernate Validator).Rückflug (return flight)