Data Transfer Objects
A DTO (Data Transfer Object) is a plain Java object used to transfer data between layers. It separates your API contract from your database model.
Why DTOs?
Entity (Database) DTO (API)
┌─────────────────┐ ┌─────────────────┐
│ id │ │ id │
│ name │ │ name │
│ passwordHash │ ← NO → │ │
│ internalField │ ← NO → │ │
│ category │ ← NO → │ categoryName │
│ reviews │ ← NO → │ averageRating │
│ createdAt │ │ │
│ updatedAt │ │ │
└─────────────────┘ └─────────────────┘
Reasons to use DTOs:
- Security — don't expose passwords, internal fields
- Flexibility — change API without changing database
- Performance — load only the data clients need
- Decoupling — API and database can evolve independently
Response DTOs
public class ProductDto {
private Long id;
private String name;
private String description;
private BigDecimal price;
private String categoryName;
private Integer reviewCount;
private Double averageRating;
// Constructors
public ProductDto() {}
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public BigDecimal getPrice() { return price; }
public void setPrice(BigDecimal price) { this.price = price; }
// ...
}
Request DTOs (Input Validation)
public class CreateProductRequest {
@NotBlank(message = "Product name is required")
@Size(min = 2, max = 255, message = "Name must be 2-255 characters")
private String name;
@Size(max = 2000, message = "Description must be at most 2000 characters")
private String description;
@NotNull(message = "Price is required")
@DecimalMin(value = "0.01", message = "Price must be at least 0.01")
private BigDecimal price;
@NotNull(message = "Category ID is required")
private Long categoryId;
@NotNull(message = "Stock quantity is required")
@Min(value = 0, message = "Stock cannot be negative")
private Integer stockQuantity;
// Getters and Setters
}
Separate DTOs for Different Operations
// Create — no ID (server generates)
public class CreateProductRequest {
private String name;
private BigDecimal price;
private Long categoryId;
}
// Update — no ID in body (ID comes from URL)
public class UpdateProductRequest {
private String name;
private BigDecimal price;
private String description;
}
// Response — includes ID and computed fields
public class ProductDto {
private Long id;
private String name;
private BigDecimal price;
private String categoryName;
private LocalDateTime createdAt;
}
Record DTOs (Java 16+)
public record ProductDto(
Long id,
String name,
String description,
BigDecimal price,
String categoryName,
Integer reviewCount,
Double averageRating
) {}
public record CreateProductRequest(
@NotBlank String name,
@Size(max = 2000) String description,
@NotNull @DecimalMin("0.01") BigDecimal price,
@NotNull Long categoryId,
@NotNull @Min(0) Integer stockQuantity
) {}
Records are immutable, concise, and include equals(), hashCode(), toString() for free.
Best Practices
Key Principles
- Follow SOLID principles
- Write clean, readable code
- Test thoroughly
- Document decisions
- Monitor in production
Implementation
- Start simple, refactor as needed
- Use established patterns
- Consider trade-offs
- Review with peers
Continuous Improvement
- Learn from incidents
- Update documentation
- Share knowledge
- Mentor others
Key Points
- Understanding DTO is essential for production systems
- Always consider scalability and maintainability
- Test thoroughly before deploying to production
- Monitor performance and set up alerting
Common Patterns
- Validation: Always validate input at the boundary
- Error Handling: Use structured error responses
- Logging: Log key events for debugging
- Testing: Unit, integration, and load tests
- Documentation: Keep docs updated with code changes
Practice Problems
Design and implement a solution for DTO in a backend system. Consider scalability, error handling, and production readiness.
Solution
// DTO implementation
// Key aspects: validation, error handling, logging, testing
public class DTO {
// Production-ready implementation
}Identify and handle edge cases for DTO. What happens under high load, with invalid input, or during failures?
Solution
// Edge case handling:
// 1. Null/empty input -> validation
// 2. High load -> rate limiting, queuing
// 3. Failures -> retries, circuit breaker
// 4. Concurrent access -> locks, idempotencyWrite a testing strategy for DTO. Include unit tests, integration tests, and performance tests.
Solution
// Test plan:
// - Unit: 80% coverage target
// - Integration: API contracts
// - Performance: latency, throughput
// - Chaos: failure injectionQuiz
1. Why should you not expose JPA entities directly as API responses?
2. What is the benefit of using Java records for DTOs?
3. What is the primary purpose of DTO?
4. What is a common mistake when implementing DTO?
Flashcards
Question
What is a DTO?
Click to reveal answer
Answer
A plain Java object used to transfer data between layers, separating API contracts from domain models
Question
Why use separate Create/Update/Response DTOs?
Click to reveal answer
Answer
Different operations need different fields — Create omits ID, Response includes computed fields
Question
What is DTO?
Click to reveal answer
Answer
DTO is a key concept in backend development.
Question
When to use DTO?
Click to reveal answer
Answer
Use DTO when building production systems that require reliability, scalability, and maintainability.
Question
DTO best practices
Click to reveal answer
Answer
Follow SOLID principles, write clean code, test thoroughly, document decisions, and monitor in production.
Revision Notes
Key Takeaways
- 1.DTOs separate API contracts from database models
- 2.Never expose entities directly — use response DTOs
- 3.Use separate DTOs for create, update, and response operations
- 4.Records (Java 16+) are ideal for immutable DTOs
- 5.Add validation annotations to request DTOs
Interview Tips
- •Explain why DTOs are needed instead of returning entities
- •Know when to use records vs regular classes for DTOs
- •Be ready to design DTOs for a given entity
Cheat Sheet
DTOs
- Purpose: Separate API from database, security, flexibility
- Types: Request DTOs (input), Response DTOs (output)
- Records: Java 16+ — immutable, concise, auto-generated methods
- Rule: Never return entities directly as API responses