Optimize your API responses using DTOs
Tags: tutorial, java, webdev, programming
Published: 2021-04-21 08:28:54

## What is it? 🧠
DTO is short for **Data Transfer Object**.

## Why do we need it? 🤔
It allows us to decouple domain objects from objects we present to the client.
It helps us present customizable views of our domain objects to the client.
It helps us deliver only the necessary data to the client, thus making our responses smaller and easier to deliver.
- As an example of this use case, there was a page in our front-end application that was taking a long time to load.
- After investigation, we noticed that the backend was sending a response with a lot of data inside of it, thus making its processing time longer.
- We then, applied the DTO principle and sent only the needed data thus resulting in **5x** faster response time.   

# How to do it? 🛠

- Get the business object from the persistence layer (database for example)
- Create a new DTO object using values from the business object
- Return the DTO to the client.

## Ok, let's code a bit ⚙️⚙️

Let's say we have a domain class called **Shipment**🚚
```java
import lombok.*;  
import java.util.Date;
@Getter @Setter @Builder @AllArgsConstructor  
public class Shipment {  
    private Integer id;  
    private Date shipmentDate;  
    private String productCode;  
    private String owner;  
    private String serialNumber;  
}
```
A mock persistence layer 🗂 (database for example) to get Shipment records 
 
```java
public class ShipmentRepository {  
// methods to get Shipment from database 
}
```
A DTO for admins' 👷🏿‍♂️ view of the Shipment
```java
import lombok.*;  
@Getter @Setter @Builder @AllArgsConstructor  
public class Shipment_AdminDTO {  
    private Integer id;  
    private String productCode;  
    private String serialNumber;  
}
```
Another DTO for users' 👷🏿‍♀️ view of the Shipment
```java
import lombok.*;  
@Getter @Setter @Builder @AllArgsConstructor  
public class Shipment_UserDTO {  
    private Date shipmentDate;  
    private String productCode;  
    private String owner;  
}
```
A service to get the Shipment from the repository, convert it to a DTO, and return it to the client
```java
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class ShipmentService {  
    private final ShipmentRepository shipmentRepository;  
  
    public Shipment_UserDTO getShipment_ForUser(Integer id){  
        return shipmentRepository.  
                getShipmentById(id).  
                map(this::getShipment_UserDTO_FromShipment).  
                orElseThrow(() -> new RuntimeException("Shipment Not Found"));  
    }  
  
    public Shipment_AdminDTO getShipment_ForAdmin(Integer id){  
        return shipmentRepository.  
                getShipmentById(id).  
                map(this::getShipment_AdminDTO_FromShipment).  
                orElseThrow(() -> new RuntimeException("Shipment Not Found"));  
    }  
      
    private Shipment_UserDTO getShipment_UserDTO_FromShipment(Shipment s){  
        return new Shipment_UserDTO(s.getShipmentDate(), s.getProductCode(), s.getOwner());  
    }  
    private Shipment_AdminDTO getShipment_AdminDTO_FromShipment(Shipment s){  
        return new Shipment_AdminDTO(s.getId(), s.getProductCode(), s.getOwner());  
    }  
}
```
An example response for an admin DTO could be:
```json
{
	"id" : "1",
	"productCode" : "VVV",
	"serialNumber" : "3XX"
}
```
An example response for a user DTO could be:
```json
{
	"shipmentDate" : "04/16/2021",
	"productCode" : "ZZZ",
	"owner" : "Jalil"
}
```
## Important Note 👇🏼 👇🏼

 it's preferable to not return a list Of DTOs as a response.

**Why?**
- Let's say in the future we would like to return another field alongside the list of DTOs, like their total count, or some other metadata.

- In that case, we might break other people's code that is using our API and expecting a list of objects to find an object with inner fields.

- If it had an object from the beginning, we could add fields to it without breaking code that uses our API.  

A code example,
```java
import lombok.*;  
@Getter @Setter @AllArgsConstructor  
public class Shipments_AdminDTO {  
    private final List<Shipment_AdminDTO> shipment_adminDTOs;  
}
```

```java
public Shipments_AdminDTO getShipments_ForAdmin(){  
    List<Shipment_AdminDTO> shipment_adminDTOS =  
            shipmentRepository.  
            getAllShipments().  
            stream().  
            map(this::getShipment_AdminDTO_FromShipment).  
            collect(Collectors.toList());  
  
    return new Shipments_AdminDTO(shipment_adminDTOS);  
}
```

This tutorial utilized **Lombok** and **Java streams**, to learn more about them check out my other posts.

 - [Lombok☄️](https://dev.to/jarjanazy/speed-up-your-java-coding-using-lombok-4b53)
 - [Java Streams🌊](https://celil-cercenazi.medium.com/from-imperative-to-declarative-in-java-2535cd01e294)

## Code on 👨🏾‍💻 [GitHub](https://github.com/Jarjanazy/java-tutorial/tree/main/src/main/java/DTOTutorial).