API를 설계하다 보면 하나의 기능에도 다양한 요청 구조가 존재할 수 있다.
예를 들어 단일 항목 등록, 다중 항목 일괄 등록, 간단한 등록, 복잡한 등록처럼 요청 방식이나 포함 필드가 달라지는 경우, 이를 어떻게 DTO 클래스로 잘 표현할 수 있을지 고민하게 된다.
따라서 이번 포스팅에서는 요청 JSON 구조에 따라 DTO를 어떻게 나누고 상속할 것인지, 그 판단 기준과 설계 전략을 정리해보려 한다.
✅ 흔히 마주치는 JSON 구조
예시로, 상품 등록 API를 설계한다고 가정했을때,
클라이언트에서 보낼 수 있는 요청은 다음과 같이 다양할 수 있습니다.
1. 단건 상품 등록
{
"productId": "P1234",
"name": "Notebook",
"price": 120000
}
2. 다건 상품 등록 (일괄 처리)
{
"products": [
{ "productId": "P1234", "name": "Notebook", "price": 120000 },
{ "productId": "P5678", "name": "Monitor", "price": 200000 }
]
}
3. 복잡한 상품 등록 (옵션 포함)
{
"productId": "P9999",
"name": "Custom PC",
"price": 1500000,
"options": [
{ "type": "RAM", "value": "32GB" },
{ "type": "SSD", "value": "1TB" }
]
}
이처럼 구조가 다르면, 하나의 DTO로 모든 요청을 처리하기보다 구조에 따라 적절히 나눈 클래스 설계가 필요하다.
🧭 DTO는 어디까지 나눠야 할까?
요청 구조가 조금만 다르다고 해서 무조건 별도의 DTO로 분리하면, 클래스 수가 지나치게 늘어나 오히려 유지보수에 불리해질 수 있다.
따라서 다음과 같은 기준을 바탕으로 DTO 분리 여부를 판단하는 것이 바람직하다.
판단 기준 | 설명 |
필드 구성이 전혀 다르다 | 항목 수, 중첩 구조, 필드 이름 등 |
검증 로직이 완전히 다르다 | 필수 여부, 값의 범위, 형식이 다를 경우 |
처리 방식이 명확히 분리된다 | 저장 방식, 비즈니스 로직 분기가 다를 경우 |
재사용 또는 API 문서화가 필요하다 | 명확한 구조 분리는 Swagger 문서화에 유리 |
✅ 위 기준을 만족하면 DTO를 분리하는 것이 유지보수성과 확장성 측면에서 훨씬 유리하다.
🧱 설계 기준 요약
구분 기준 | 설명 |
공통 필드 | 모든 요청에서 공통되는 필드는 BaseRequestDto로 추출 |
요청 구조 | 단건 vs 다건, 단순 vs 복잡 요청은 서로 다른 DTO로 분리 |
선택적 구성 요소 | 옵션 등 일부 요청에서만 필요한 필드는 별도 클래스 또는 상속으로 구성 |
검증 기준 분리 | 각 요청 구조에 따른 검증 로직을 DTO 레벨에서 구분 가능 |
📦 DTO 클래스 설계 예시
공통 DTO
// 공통 필드 추출
public class BaseProductDto {
private String productId;
private String name;
private int price;
}
단건 등록 요청 DTO
public class SimpleProductRequestDto extends BaseProductDto {
// 단건 등록에는 추가 정보 없음
}
복잡 요청 DTO(옵션 포함)
public class ComplexProductRequestDto extends BaseProductDto {
private List<ProductOptionDto> options;
}
public class ProductOptionDto {
private String type;
private String value;
}
다건 요청 DTO
public class BulkProductRequestDto {
private List<SimpleProductRequestDto> products;
}
💡이렇게 분리하면 좋은 이유
이점 | 설명 |
유형별 검증/처리 용이 | 단건/다건/복잡 요청을 각각 명확히 구분하여 검증과 핸들링 가능 |
확장성 확보 | 새로운 요청 구조가 생겨도 기존 클래스를 건드릴 필요 없음 |
API 문서 자동화 용이 | Swagger/OpenAPI에서 구조가 명확히 드러남 |
가독성과 유지보수성 향상 | 불필요한 null 필드나 조건문 없는 깔끔한 코드 가능 |
마무리
DTO는 단순한 데이터 묶음이 아니라, API 요청 구조를 명확히 표현하는 설계 요소다.
요청 구조가 다를수록 공통 필드는 상속, 유형별로 분리하는 방식이 더 적절하다는 걸 알게 되었다.
앞으로는 요청 구조에 맞는 DTO를 신중하게 나누는 설계를 통해 더 깔끔하고 확장 가능한 API를 만들고자 한다.
'Backend > Architecture' 카테고리의 다른 글
전략 패턴과 팩토리 패턴으로 서비스 로직 가독성 높이기 (2) | 2025.07.15 |
---|---|
추상 클래스 vs 인터페이스, 언제 어떤 걸 써야 할까? (1) | 2025.07.14 |
VO에 Lombok을 쓰면 안 되는 이유 (0) | 2025.07.02 |
API 요청과 DB 컬럼이 다를 때, DTO와 VO를 나누는 이유 (0) | 2025.07.01 |
MVC에 익숙했던 내가 도메인 구조를 선택한 이유 (2) | 2025.06.28 |