DTO Nedir? Spring Boot’ta Entity vs DTO Farkı ve MapStruct Kullanımı (2026)

DTO (Data Transfer Object), özellikle Java ve Spring Boot ile geliştirilen REST API'lerde verinin güvenli, kontrollü ve hafif biçimde taşınmasını sağlayan sade nesnelerdir.

Bu rehberde şu sorulara net cevap bulacaksınız: DTO nedir, ne demek?, DTO ne işe yarar?, Entity vs DTO farkı nedir?, MapStruct ile DTO nasıl oluşturulur?

DTO (Data Transfer Object) nedir? Spring Boot ile DTO kullanımı ve Entity vs DTO farkı — 2026
DTO, API çıktısını kontrol ederek güvenliği artırır ve bakım maliyetini düşürür.

DTO Nedir? Ne Demek?

DTO (Data Transfer Object), uygulamanın dış sistemlerle — örneğin bir REST API istemcisiyle — veri alışverişi yaparken kullandığı, iş mantığı içermeyen ve yalnızca veri taşıyan nesnelerdir. Martin Fowler'ın Patterns of Enterprise Application Architecture kitabında tanımladığı bu tasarım örüntüsü, Java dünyasında özellikle Spring Boot projeleri için fiili standart haline gelmiştir.

Temel amaç: Veritabanı modelini (Entity) doğrudan dış dünyaya açmadan, kontrollü ve sözleşmeli bir API çıktısı sunmak.

Kısaca: Entity veritabanının dilidir, DTO ise API'nin dilidir. İkisi birbirinden ayrı tutulduğunda katmanlar arası bağımlılık azalır, güvenlik artar ve bakım kolaylaşır.

Spring Boot mimarisinde Entity'den DTO'ya dönüşüm akışı — Controller Service Repository katmanları
Controller → Service → Repository → Entity → Mapper → DTO → Response

Neden DTO Kullanılır? DTO Ne İşe Yarar?

Entity sınıfını doğrudan API yanıtı olarak döndürmek kısa vadede pratik görünse de gerçek dünya projelerinde ciddi sorunlara yol açar. DTO kullanmanın üç temel nedeni vardır:

1) Güvenlik

Entity sınıfı genellikle password, createdAt, internalStatus gibi hassas ya da gereksiz alanlar içerir. Entity doğrudan döndürüldüğünde bu alanlar istemeden API yanıtına dahil olabilir. DTO yalnızca açıkça tanımlanan alanları taşıdığından hassas veri sızıntısı önlenir.

2) API Stabilitesi

Veritabanı şeması değiştiğinde Entity sınıfı da değişir. Eğer Entity doğrudan kullanılıyorsa bu değişiklik tüm istemcileri kırar. DTO bağımsız bir API sözleşmesi oluşturduğundan, veritabanı değişse bile API yanıtı sabit kalabilir.

3) Performans

Entity tüm veritabanı alanlarını içerir. Ağ üzerinden yalnızca gerekli alanların gönderilmesi JSON payload boyutunu küçültür, bant genişliği tüketimini azaltır ve özellikle mobil istemcilerde belirgin bir hız farkı yaratır.

DTO ile Spring Boot API güvenliği — hassas alanların dışarıya açılmaması
Sadece gerekli alanlar DTO aracılığıyla dış dünyaya açılır.

Entity vs DTO Farkı Nedir?

Entity ve DTO'nun sorumluluklarını karıştırmak Spring Boot projelerinde sık karşılaşılan bir hatadır. Aşağıdaki tablo temel farkları özetler:

ÖzellikEntityDTO
AmaçVeritabanı modeliAPI sözleşmesi
KatmanPersistence (JPA)Presentation / Service
Anotasyon@Entity, @Table, @ColumnGenellikle sade POJO veya record
GüvenlikTüm alanları açar — riskliYalnızca tanımlanan alanlar
Değişiklik etkisiVeritabanıyla bağlıAPI'den bağımsız
ValidationDB kısıtlamaları@NotNull, @Email, @Size
Kural: Entity hiçbir zaman doğrudan @RestController'dan döndürülmemelidir.

Spring Boot DTO Örneği

Aşağıda basit bir müşteri entity'si ve ona karşılık gelen DTO örneği verilmiştir:

Entity (veritabanı modeli):

@Entity
@Table(name = "customers")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String firstname;
    private String lastname;
    private String email;
    private String password;         // API'ye açılmamalı
    private LocalDateTime createdAt; // API'ye açılmamalı
}

DTO (API sözleşmesi — yalnızca gerekli alanlar):

public class CustomerDto {
    private Long id;
    private String firstname;
    private String lastname;
    private String email;
    // password ve createdAt burada YOK
}

Bu yapıda password ve createdAt alanları API yanıtına hiçbir zaman dahil edilmez.


MapStruct ile Entity → DTO Dönüşümü

Entity'den DTO'ya dönüşümü manuel yazmak hem zahmetlidir hem de hata riski taşır. MapStruct, bu dönüşümü derleme zamanında (compile-time) otomatik oluşturan bir kütüphanedir. Reflection kullanmadığı için ModelMapper gibi alternatiflere göre belirgin biçimde daha hızlıdır.

pom.xml bağımlılığı:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.5.Final</version>
</dependency>

Mapper arayüzü:

@Mapper(componentModel = "spring")
public interface CustomerMapper {
    CustomerDto toDto(Customer customer);
    Customer toEntity(CustomerDto dto);
    List<CustomerDto> toDtoList(List<Customer> customers);
}

Service katmanında kullanımı:

@Service
@RequiredArgsConstructor
public class CustomerService {
    private final CustomerRepository repository;
    private final CustomerMapper mapper;

    public CustomerDto getById(Long id) {
        Customer customer = repository.findById(id)
            .orElseThrow(() -> new RuntimeException("Müşteri bulunamadı"));
        return mapper.toDto(customer);
    }
}

MapStruct, toDto() metodunun implementasyonunu derleme sırasında otomatik oluşturur. Reflection içermediğinden runtime overhead sıfırdır.


Request DTO vs Response DTO

Gerçek projelerde istek (request) ve yanıt (response) için ayrı DTO sınıfları tanımlamak en iyi yaklaşımdır. Böylece validation kuralları ve dönen alanlar birbirinden bağımsız yönetilebilir:

Request DTO — gelen veriyi doğrular:

public class CreateCustomerRequest {
    @NotBlank(message = "Ad boş olamaz")
    private String firstname;

    @NotBlank(message = "Soyad boş olamaz")
    private String lastname;

    @Email(message = "Geçerli bir e-posta girin")
    @NotBlank
    private String email;

    @Size(min = 8, message = "Şifre en az 8 karakter olmalı")
    private String password;
}

Response DTO — dış dünyaya açılan alanlar:

public class CustomerResponse {
    private Long id;
    private String firstname;
    private String lastname;
    private String email;
    // password burada YOK
}

Controller katmanında kullanımı:

@PostMapping("/customers")
public ResponseEntity<CustomerResponse> create(
        @RequestBody @Valid CreateCustomerRequest request) {
    CustomerResponse response = customerService.create(request);
    return ResponseEntity.status(HttpStatus.CREATED).body(response);
}

Java Record ile DTO (Java 17+)

Java 16 ile tanıtılan record yapısı, immutable DTO oluşturmanın en modern ve özlü yoludur. Getter, equals, hashCode ve toString metodlarını otomatik oluşturur:

public record CustomerDto(
    Long id,
    String firstname,
    String lastname,
    String email
) {}

Record'lar değiştirilemez (immutable) olduğundan thread-safe'dir ve yanlışlıkla veri değiştirme riskini ortadan kaldırır. Spring Boot 3.x ile tam uyumludur.

Not: Record'lar varsayılan olarak final'dır ve kalıtıma izin vermez. Eğer mevcut DTO sınıflarını genişletiyorsanız klasik POJO yaklaşımını tercih edin.


DTO Best Practices (2026)

  • Entity'yi asla doğrudan döndürme. @RestController metodları her zaman DTO döndürmeli.
  • Request ve Response DTO'larını ayır. Aynı sınıfı hem giriş hem çıkış için kullanmak zamanla yönetilemez hale gelir.
  • Validation anotasyonlarını Request DTO'da kullan. @NotNull, @Email, @Size gibi kısıtlamaları doğrudan DTO'ya ekle.
  • MapStruct tercih et, ModelMapper'dan kaçın. Compile-time mapping daha hızlı ve tip güvenlidir.
  • API versiyonlamasını DTO ile yönet. CustomerDtoV1, CustomerDtoV2 gibi ayrı DTO'lar geriye dönük uyumluluğu korur.
  • Java 17+ kullanıyorsan record değerlendir. Özellikle salt okunur yanıt DTO'ları için idealdir.

Sık Sorulan Sorular

DTO kullanmak zorunlu mu?

Teknik olarak zorunlu değildir. Küçük, kişisel projelerde Entity doğrudan kullanılabilir. Ancak üretim ortamındaki her gerçek dünya projesinde DTO kullanımı güçlü biçimde önerilen bir pratiktir. Güvenlik açıkları, API kırılmaları ve bakım güçlükleri genellikle DTO kullanılmadığı projelerde ortaya çıkar.

DTO ile POJO arasındaki fark nedir?

POJO (Plain Old Java Object), herhangi bir framework'e veya arayüze bağlı olmayan sade Java sınıfıdır. DTO bir tasarım örüntüsüdür ve amacı veri taşımaktır. Her DTO bir POJO'dur, ancak her POJO bir DTO değildir.

Projection mı DTO mu kullanmalıyım?

Projection, JPA sorgu düzeyinde yalnızca belirli alanları çeker ve veritabanı performansı için iyidir. DTO ise API sözleşmesini ve servis katmanı veri transferini temsil eder. İkisi birlikte kullanılabilir: JPA projection ile veritabanından az veri çekin, ardından bunu response DTO'ya dönüştürün.

DTO'da iş mantığı olabilir mi?

Hayır. DTO yalnızca veri taşımalıdır. Hesaplama, doğrulama veya dönüştürme mantığı service katmanında kalmalıdır. DTO'ya iş mantığı eklemek sorumlulukları karıştırır ve test edilebilirliği azaltır.

Lombok ile DTO nasıl kullanılır?

Lombok'un @Data, @Getter, @Setter ve @Builder anotasyonları DTO sınıflarında yaygın olarak kullanılır. Özellikle @Builder, DTO nesnelerini test kodunda kolayca oluşturmayı sağlar.


Sonuç

DTO kullanımı Spring Boot API'lerini daha güvenli, sürdürülebilir ve ölçeklenebilir hale getirir. Entity'yi doğrudan dışa açmak kısa vadede hız kazandırır gibi görünse de ilerleyen süreçte güvenlik açıkları, API kırılmaları ve bakım güçlükleri doğurur.

MapStruct ile dönüşümleri otomatikleştirin, Request/Response DTO'larını ayırın ve Java record yapısını değerlendirin. Bu üç adım bile projenizin uzun vadeli kalitesini önemli ölçüde artırır.

İlgili diğer yazılar:

Latest Software Developers - Yazılım Blog Yazarı Profil Resmi

Yazar

LatestSoftwareDevelopers

Güncel yazılım teknolojilerinin takip edildiği blog.

Spring Boot ile ilgili yorumlar

Yorum Paylaş

EMail Zorunlu alanlar * *