0

I'm a junior developer and started my first job as a developer and have a question regarding DTO and Model.

Consider this code snippet

@Override
    public ResponseEntity<List<PostalCodeLocationModel>> findPostcalCodeLocationPairs(final PostalCodeLocationSearchModel model) {
        final String postalCode= model.getPostalCode();
        final String location = model.getLocation();

        final List<PostalCodeLocationModel> listOfPostalCodeLocationPairs = service.findPostalCodeLocationPairs(plz, ort).stream()
                .map(mapper::dtoToModel)
                .toList();

        return ResponseEntity.ok(listOfPostalCodeLocationPairs);
    }

Or

@Override
    public ResponseEntity<UserReadModel> getUserData(final String name) {
        UserDTO dto = service.getUser(user);
        UserReadModel iserReadModel = mapper.dtoToModel(dto);
        return ResponseEntity.ok(userReadModel);
    }

A similar approach is used in the project I am working on. I am a bit confused because what I have learned is, that in this layer where the Controller is, always map to DTO in the end and send the DTO but here, the service is returning a DTO which is then mapped to the model and return. Is this approach correct?

I always did like that in the past and one of my old projects:

@ApiOperation(value = "Get Enterprises within Radius", notes = "Retrieves enterprises within the given radius from a geographical point")
    @GetMapping("/within-radius")
    public ResponseEntity<List<EnterpriseDto>> getObjectsWithinRadius(@RequestParam double lat, @RequestParam double lng, @RequestParam double radius) {
        List<Enterprise> enterprises = enterpriseService.getEnterprisesWithinRadius(lat, lng, radius);
        List<EnterpriseDto> enterpriseDtos = enterpriseMapper.toDtos(enterprises);
        return new ResponseEntity<>(enterpriseDtos, HttpStatus.OK);
    }

Here I use the service with the parameters and get back an Enterprise object and map it to a DTO which I will return.

2
  • What happens underneath, in the service. methods? Is it the case of duplicate conversion, e.g. UserReadModel -> UserDTO -> UserReadModel? Commented May 23 at 13:06
  • 1
    The question is hard to answer because the term "Model" can refer to either an Entity in the database or a DTO — it depends on the person. The main idea is that it's good practice to divide logic into layers; simply put: controller → service → repository. The controller should not use entities (should not know about them), and should operate with DTOs instead. To gain more info about it - there are thousands of resources/articles on the internet about this Commented May 23 at 19:11

4 Answers 4

1

In a typical multi-layered application, the Model usually refers to the database entity (a class that is directly mapped to a table in the database). On the other hand, a DTO (Data Transfer Object) is used to transfer data between layers of the application, particularly when you want to decouple internal models from external representations.

However, some companies may not strictly follow this naming convention. For example, they might suffix their database entities with "DTO" or refer to DTOs as "models." While this isn't necessarily a bad practice, it can lead to confusion, especially for junior developers who are trying to understand the architecture.

Typical Flow in a Multi-Layered Application:

  1. View (Frontend):
    Sends user input and requests to the backend.

  2. Controller:
    Receives data from the frontend and forwards it to the service layer. It may also handle some light aggregation or orchestration logic.

  3. Service Layer:
    Fetches entities from the DAO, performs business logic, and maps entities to DTOs (if needed).

  4. DAO (Data Access Object):
    Handles CRUD operations and returns entities from the database.

  5. Backflow:

    • DAO returns entities to the Service layer.

    • Service processes data, applies business logic, and returns a DTO to the Controller.

    • Controller sends the processed data back to the View (frontend).

In some projects, DTO mapping may also occur at the controller level. This depends on the architectural design and project requirements. However, directly exposing database entities to the frontend is generally discouraged. Instead, entities should be converted to DTOs that only include the required fields. This ensures encapsulation, enhances security, and prevents unnecessary data exposure from the database schema.

Sign up to request clarification or add additional context in comments.

Comments

0

The purpose of DTO is that your controller returns an object in your API that is separate from your core entities.

If you have a core entity called Transaction that contains an object of type Currency, it is a bad practice to return Transaction and leak to the outside that your transaction has a type Currency in it, instead you create a DTO and in the DTO format the currency to a String, this way your entities preserved and hidden from what your controller returns. Now your API and core entities can change independently without breaking each other.

The correct order is that services will return model entities, and in your controller, they are mapped to a DTO.

Comments

0

Basic points to consider while designing Model and DTO,

  1. Entity (Model)
  • Represents a database table (JPA @Entity).

  • Should only exist in the persistence/data layer.

  • Example: User, Enterprise

  1. DTO (Data Transfer Object)
  • Used to transfer data between layers or as a response payload.

  • Exists in the API/controller layer.

  • Example: UserDto, EnterpriseDto, UserReadModel, etc.

  1. Service Layer
  • Does the business logic and talks to repositories.

  • Should ideally work with Entities/Models and maybe some internal DTOs.

  • Should not know about UserReadModel or PostalCodeLocationModel if they are meant only for the controller.

Comments

0

Returning DTOs is preferred because of below points:

  • You can hide sensitive fields (e.g., passwords, internal IDs).

  • Prevent exposing your full internal data model (which can change over time).

  • Return only the data needed by the client — not large unused fields like blobs.

  • You can tailor the DTO to the frontend's needs (nested objects, flattened data, computed fields).

  • Entities might have lazily loaded relationships (@OneToMany, etc.), which cause exceptions when serialized.

  • your persistence layer (entities) from being tightly coupled with the API layer.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.