mr.nothing
mr.nothing

Reputation: 5399

Application layers in Spring application

I'm participating in implementing rest API application and we're sticking to Spring Boot as a framework.

We're at the very beginning of implementing the system but even at this stage of the project, it starts to feel like it is something wrong with application design.

We have 3 layers in our application:

  1. Controller layer - at this layer we (some of this is done automatically by spring):
    • receive requests from our clients
    • convert it to dto object and validate this dto
    • convert dto and logged in user information to some object or DB entity (!) to make a call of the Service layer.
    • return result to the client as dto object which is converted from some object or DB entity (!)
  2. Service level - at this layer we:
    • do all the business logic, e.g. external services calls
    • change/create/delete entities via Repository layer calls
    • return result of the business logic as some object or DB entity object (!)
  3. Repository level - at this level we specify the logic which returns database entities to the Service level.
    • make queries to our DB to get entity and return it as is to the service layer

My concern about application design described above:

  1. All application layers know about DB entities
  2. It should be pretty difficult to control sessions, transactions and all the stuff at a minimum in cases when entities have lazy-fetched proxies.
  3. Not sure, if we need to, but we can introduce some type of ServiceDto so the contract is the following:
    • Controller coverts validated client dto to ServiceDto and call Service layer with it as an input
    • Service performs business logic with the use of ServiceDto and convert the result of business operations and ServiceDto to DB entity and calls Repository layer with it as an input
    • Repository accepts db entities and returns DB entities as it was before
    • The only thing that can be pretty harsh here is a mapping between all these DTOs

It will really help to see some type of guidelines, best practices or projects which shows how to organize communications between application layers in this type of application.

Thanks a lot!

Additions below

Some code snippets:

class OrderController {
    @Autowired
    private OrderService orderService;
    @Autowired
    private UserService userService;
    public OrderResultDto createOrder(OrderRequestDto dto) {
        return orderService.makeOrderRequest(userService.getAuthenticatedUser(), dto)
    }
}

class OrderService {
    @Autowired
    private OrderRepository orderRepo;

    public makeOrderRequest(User user, OrderRequestDto dto) {
        // do some complex business logic
    }
}

It seems not ok to assign dto we send to frontend as JSON to Service contract... Moreover, if we need to call this service from another method, that method will be bound to this dto as well which is not good.

Upvotes: 1

Views: 2346

Answers (1)

Robert Bain
Robert Bain

Reputation: 9586

The controller layer is the web facing layer. Its job is to accept input and generally speaking, convert it into a format for use with the service layer and call the service. As you say, Spring does this conversion out of the box, E.G. modeling JSON into a DTO based on the type of controller method parameter.

convert dto and logged in user information to some object or db entity (!) to make a call of the Service layer. return result to client as dto object which is converted from some object or db entity (!)

This is poor separation of abstractions. How would you manage transactions, for instance? It's also dangerous exposing a "live" JPA entity to the web layer. Furthermore, the web is just one way you may want to interact with your services. What would happen if you want to run your service as a scheduled job using, E.G. Quartz? The conversion from JPA entity to DTO and back should be done in the service layer, as should transaction management.

return result of the business logic as some object or db entity object (!) Again, the service should be mapping entities to DTOs. There should be no objects leaking from the repository out of the service.

The controller can do the automatic conversation to the DTO and that can be the input/output to/from the service. E.G. controller accepts a PersonDTO, Spring performs the mapping to the DTO with jsr-303 bean validation, the service is called with the PersonDTO, maps the DTO to an entity, calls the repository layer, maps the returned entity to a DTO then returns the DTO.

From your question, it sounds like you're very much thinking along the right lines. The only thing I'd question is the need for controller DTOs and service DTOs. Using the same class for this is fine.

Upvotes: 1

Related Questions