Home > Backend Development > πŸ“š[Backend Development] Request/Response DTO의 상세 ꡬ쑰.

πŸ“š[Backend Development] Request/Response DTO의 상세 ꡬ쑰.
Backend Ddevelopment API Layer Architecture DTO

πŸ“š[Backend Development] Request/Response DTO의 상세 ꡬ쑰.

DTO의 상세 κ΅¬μ‘°λŠ” β€˜μ–΄λ–€ 역할을 ν•˜λŠλƒβ€™ 에 따라 λ‹¬λΌμ§‘λ‹ˆλ‹€.
Request DTOλŠ” 데이터λ₯Ό λ°›μ•„ κ²€μ¦ν•˜λŠ” 것에, Response DTOλŠ” 데이터λ₯Ό 보기 μ’‹κ²Œ κ°€κ³΅ν•˜μ—¬ λ³΄μ—¬μ£ΌλŠ” 것에 μ΄ˆμ μ„ 맞μΆ₯λ‹ˆλ‹€.

πŸ“¦ Request DTO의 상세 ꡬ쑰.

Request DTOλŠ” ν΄λΌμ΄μ–ΈνŠΈλ‘œλΆ€ν„° λ“€μ–΄μ˜€λŠ” 데이터λ₯Ό μ•ˆμ „ν•˜κ²Œ λ°›μ•„λ‚΄κΈ° μœ„ν•œ ꡬ쑰λ₯Ό κ°€μ§‘λ‹ˆλ‹€.

  • ν•„λ“œ (Fields)
    • API μš”μ²­ λ³Έλ¬Έ(Request Body)의 JSON key와 μΌμΉ˜ν•˜λŠ” 멀버 λ³€μˆ˜λ“€λ‘œ κ΅¬μ„±λ©λ‹ˆλ‹€.
  • 검증 μ–΄λ…Έν…Œμ΄μ…˜ (Validation Annotations)
    • @NotBlank, @NotNull, @Size, @Pattern λ“± jakarta.validation μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜μ—¬, λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ— λ„λ‹¬ν•˜κΈ° 전에 데이터가 μœ νš¨ν•œμ§€ κ²€μ‚¬ν•©λ‹ˆλ‹€.
      • 이것이 Request DTO의 κ°€μž₯ μ€‘μš”ν•œ νŠΉμ§•μž…λ‹ˆλ‹€.
  • κΈ°λ³Έ μƒμ„±μžμ™€ Getter
    • JSON 데이터λ₯Ό 객체둜 λ³€ν™˜(Deserialization)ν•˜κΈ° μœ„ν•΄ Lombok의 @NoArgsConstructor와 @Getterλ₯Ό 주둜 μ‚¬μš©ν•©λ‹ˆλ‹€.

μ½”λ“œ μ˜ˆμ‹œ : ProductCreateRequestDto.java

@Getter
@NoArgsConstructor // JSON λ³€ν™˜μ„ μœ„ν•œ κΈ°λ³Έ μƒμ„±μž
public class ProductCreateRequestDto {
    
    @NotBlank(message = "μƒν’ˆλͺ…은 ν•„μˆ˜μž…λ‹ˆλ‹€.")
    @Size(max = 100, message = "μƒν’ˆλͺ…은 100자λ₯Ό λ„˜μ„ 수 μ—†μŠ΅λ‹ˆλ‹€.")
    private String productName;
    
    @NotNull(message = "νŒλ§€κ°€λŠ” ν•„μˆ˜μž…λ‹ˆλ‹€.")
    @Positive(message = "νŒλ§€κ°€λŠ” 0보닀 컀야 ν•©λ‹ˆλ‹€.")
    private BigDecimal productSaleCost;
    
    // ... μš”μ²­μ— ν•„μš”ν•œ λ‹€λ₯Έ ν•„λ“œμ™€ 검증 κ·œμΉ™λ“€ ...
}

πŸ“¦ Response DTO의 상세 ꡬ쑰.

Response DTOλŠ” μ„œλ²„μ˜ 처리 κ²°κ³Όλ₯Ό ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œ λͺ…ν™•ν•˜κ³  μ‚¬μš©ν•˜κΈ° νŽΈν•œ ν˜•νƒœλ‘œ 보여주기 μœ„ν•œ ꡬ쑰λ₯Ό κ°€μ§‘λ‹ˆλ‹€.

  • ν•„λ“œ (Fields)
    • Entity의 데이터λ₯Ό κ·ΈλŒ€λ‘œ 보여주기도 ν•˜κ³ , μ—¬λŸ¬ Entity의 정보λ₯Ό μ‘°ν•©ν•˜κ±°λ‚˜ Serviceμ—μ„œ κ³„μ‚°λœ 값을 ν¬ν•¨ν•˜κΈ°λ„ ν•©λ‹ˆλ‹€.
    • 예: margin, totalStockCount
  • λΆˆλ³€μ„± (Immutability)
    • μ‘λ‹΅μœΌλ‘œ λ‚˜κ°€λŠ” 데이터가 쀑간에 λ³€κ²½λ˜μ§€ μ•Šλ„λ‘ final ν•„λ“œμ™€ μƒμ„±μž(@Builder ν™œμš©)λ₯Ό μ‚¬μš©ν•˜μ—¬ λΆˆλ³€ 객체둜 λ§Œλ“œλŠ” 것이 쒋은 νŒ¨ν„΄μž…λ‹ˆλ‹€. setterλŠ” μ‚¬μš©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
  • 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œ (Static Factory Method)
    • Entity 객체λ₯Ό DTO 객체둜 λ³€ν™˜ν•˜λŠ” λ‘œμ§μ„ DTO 내뢀에 정적 λ©”μ„œλ“œ(e.g, from(Product product))둜 λ§Œλ“€μ–΄λ‘λ©΄, Service κ³„μΈ΅μ˜ μ½”λ“œλ₯Ό 더 κΉ”λ”ν•˜κ²Œ μœ μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ½”λ“œ μ˜ˆμ‹œ: ProductResponseDto.java

@Getter
public class ProductResponseDto {
    
    private final Long productId;
    private final String productName;
    private final BigDecimal fianlSalePrice; // κ³„μ‚°λœ μ΅œλ™ νŒλ§€κ°€
    private final int totalStockCount; // κ³„μ‚°λœ 총재고
        
    // DTOλŠ” λΆˆλ³€μ„±μ„ μœ„ν•΄ Builderλ₯Ό ν†΅ν•œ μƒμ„±μžλ§Œ ν—ˆμš©
    @Builder
    
    private ProductResponseDto(Long productId, String productName, BigDecimal finalSalePrice, int totalStockCount) {
        this.productId = productId;
        this.productName = productName;
        this.finalSalePrice = finalSalePrice;
        this.totalStockCount = totalStockCount;
    }
    
    // Entityλ₯Ό DTO둜 λ³€ν™˜ν•˜λŠ” 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œ
    public static ProductResponseDto from(Product product, int totalStockCount) {
        return ProductResponseDto.builder()
            .productId(product.getProductId())
            .productName(product.getProductName())
            .finalSalePrice(calculateFinalPrice(product.getProductSaleCost(), product.getProductDiscountRate()))
            .totalStockCount(totalStockCount)
            .build();
    }
    
    private static BigDecimal calculateFinalPrice(BigDecimal saleCost, Integer discountRate) {
        // ... 가격 계산 둜직 ...
    }
}