Architecture & Layers
Architecture
The backend uses the Controller-Service-Repository pattern. This pattern consist of different layers. Each layer has a different task.
block-beta
columns 5
A["Controller"]:5
Arrow1<[" "]>(down):5
B["Service"]:3 Arrow4<[" "]>(x):1 M["Mapper"]:1
Arrow2<[" "]>(down):5
C["JPA-Repository"]:3 Arrow5<[" "]>(x):1 E["Models"]:1
Arrow3<[" "]>(down):5
D[("Database")]:5
style Arrow1 fill:#D3D3D3,stroke:#666666
style Arrow2 fill:#D3D3D3,stroke:#666666
style Arrow3 fill:#D3D3D3,stroke:#666666
style Arrow4 fill:#D3D3D3,stroke:#666666
style Arrow5 fill:#D3D3D3,stroke:#666666
Layers
Controller
This is the entry point of the application. It mainly uses Jakarta RESTful Web Services (JAX-RS) annotations. These resources handle incoming HTTP requests and call the appropriate methods of the service layer to perform the actual business logic.
| Example | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
- Injecting service in controller layer to access business logic
- Specify the HTTP-method of the endpoint
- Specify the name of the endpoint
- Call method of the service layer for the actual business logic
Service
Service layer is responsible for the actual business logic. It performs calculations, validations independent of how the the actual incoming request was served. It uses mappers to convert between DTOs and Entities. The purpose is to decouple how data is persisted and how it is served through the API. It also protects sensitive data from being exposed.
This ensures:
- Decoupling: Separates internal database logic from the external interface
- Security: Prevents internal fields (e.g., passwords) from being exposed
- Stability: Ensures database changes don't break the public API
| Example | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
- Turn the DTO of the request into a entity, mapping it to a database model
- Call method of repository layer to save entity
- Return response DTO
To retreive data of the database, the service layer is accessing the repository layer.
Repository
The repository layer abstracts all database interaction. It sole purpose is to perform operations on the database. It uses Jakarta Persistence (JPA) to abstractes from the complexity of SQL or JPA queries and database drivers (JDBC) from the service layer. It remains database-independent, unless dialect-specific native queries are used.
Panache sits on top of this layer to reduce boilerplate code. With Panache, it is possible to write a short expression like find("project.id", projectId) and it will automatically generates the corresponding SQL query. It aims to reduce boilerplate-code.
| Example | |
|---|---|
1 2 3 4 5 | |
Source Code
The architecture is directly reflected on to the soure code structure
| Structure of backend source code | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
- Repository for database access
- Data Transfer Objects
- Custom exceptions, useful for endpoints to return more information on error
- Converting between DTOs and entities
- Business entities, used by JPA for persistance in the database
- API handling incoming HTTP requests
- Business logic