image.png

개발을 시작한 지 한 달이 지났다. 백엔드 개발자 승준이와 준규는 각자 열심히 API를 만들고 있었다. 프론트엔드 개발자 윤표가 합류하면서 개발 속도는 더 빨라졌다. 그런데 문제가 생겼다. 승준이의 API 응답과 준규의 API 응답이... 달랐다.

이유은 아주 단순하게도 둘 다 한 번도 **“응답 규격을 맞춰본 경험”**이 없었던 것이다.

매주 회의 때마다 "이 API는 어떤 형식이야?" 라는 질문이 반복됐고, 윤표는 API를 쓸 때마다 응답 구조를 새로 파악해야 했다. 소통 비용이 쌓이기 시작했다.

이 글은 그 문제를 해결하는 과정과, 최종적으로 ResponseEntity + @RestControllerAdvice 를 선택한 이유를 기록한다.


문제 상황

승준이는 제네릭 DTO로 감싸서 전달했다.

public class ApiResponseDto {
    @Data
    @AllArgsConstructor
    public static class ApiResponse<T> {
        private T data;  // data 필드 하나만 존재
    }
}

준규는 영속성 컨텍스트에서 캐싱되는 DTO를 그대로 전달했다.

결과는 이랬다.

// 승준이 API
{ "data": { ... } }

// 준규 API
{ "id": 1, "name": "..." }

프론트 입장에서는 API마다 응답 구조가 달라 매번 확인이 필요했다. 성공인지 실패인지도 응답만 봐서는 알 수 없었다.

어떻게 해결할 수 있을까?


해결책. ResponseEntity + 정적 팩토리 메소드

ResponseEntity는 스프링에서 HTTP 응답 전체를 표현하는 클래스다.

단순히 데이터만 보내는 게 아니라 상태 코드, 헤더, 본문을 모두 담아 보낼 수 있다.

원리

생성자를 **private**으로 막고, 상황별 정적 팩토리 메소드만 열어둔다.