20250102 TIL : 공통 응답 DTO 적용기와 HTTP Status Code 적용하기

MCS·2025년 1월 2일

TIL

목록 보기
36/45

오늘 학습한 내용

  • 공통 응답 DTO 적용기와 HTTP Status Code 적용하기
    • 공통 응답 DTO 적용기
    • HTTP Status Code 적용

공통 응답 DTO 적용기와 HTTP Status Code 적용하기

공통 응답 DTO를 작성하고 적용하는 과정에서 있었던 과정들을 기록해보았다.

공통 응답 DTO 적용기

최초에 공통 응답 DTO를 다음과 같이 작성했다.

@Getter
@Builder
public class ResponseDTO<T> {
	private Integer status;
    private String message;
    private T data;
    
    public static <T> ResponseDTO<T> of(Integer status, String message, T data) {
        return ResponseDTO.<T>builder()
        		.status(status)
                .message(message)
                .data(data)
                .build();
    }
}

그리고 컨트롤러에서 다음과 같이 사용했다.

@PostMapping("/signup")
    public ResponseEntity<ResponseDto<ResPostSignUpDto>> signUp(@RequestBody ReqPostSignUpDto requestDto) {

        ResPostSignUpDto resPostSignUpDto = ResPostSignUpDto.builder()
                .userId(UUID.randomUUID())
                .build();

        ResponseDto<ResPostSignUpDto> responseDto = ResponseDto.of(201, "회원가입 성공", resPostSignUpDto);

        return ResponseEntity.status(HttpStatus.CREATED).body(responseDto);
    }

ResponseEntity<ResponseDto<ResPostSignUpDto>> 와 같이 ResponseEntity로 감싼 리턴 타입을 사용했는데, 가독성이 떨어진다는 의견이 있었다. 그래서 ResponseDto를 리턴 타입으로 사용하도록 하고, ResponseDto를 다음과 같이 수정했다.

@Getter
@Builder
public class ResponseDto<T> {
    private HttpStatus status; 
    private String message;
    private T data;

    // 성공 응답
    public static <T> ResponseDto<T> ok(String message, T data) {
        return ResponseDto.<T>builder()
                .status(HttpStatus.OK)
                .message(message)
                .data(data)
                .build();
    }

    // 생성 응답
    public static <T> ResponseDto<T> created(String message, T data) {
        return ResponseDto.<T>builder()
                .status(HttpStatus.CREATED)
                .message(message)
                .data(data)
                .build();
    }

    // 잘못된 요청 응답
    public static <T> ResponseDto<T> badRequest(String message) {
        return ResponseDto.<T>builder()
                .status(HttpStatus.BAD_REQUEST)
                .message(message)
                .data(null)
                .build();
    }

    // 커스텀 응답 (HTTP 상태를 직접 설정)
    public static <T> ResponseDto<T> of(HttpStatus status, String message, T data) {
        return ResponseDto.<T>builder()
                .status(status)
                .message(message)
                .data(data)
                .build();
    }
}

여기서 문제가 하나 발생했는데, 지금 공통 응답 DTO에 status가 있긴 하지만, 이것이 실제 응답의 status code로는 연결되지 않는다. 이것은 커스텀 응답 코드를 사용하고 모든 응답을 200 OK로 돌려줄 것이라면 적절할 수 있겠지만, 만약 응답의 status code를 지정하려고 한다면 다른 방법을 사용해야 한다.(개인적으로는 응답의 status code를 반드시 지정하는 것을 선호한다.)

HTTP Status Code 적용

HTTP Status Code를 적용하는 방법에는 여러 가지가 있다.

처음 적용했던 ResponseEntity로 감싸는 방법이 있지만, 가독성이 떨어지는 문제로 인해 사용하지 않기로 결정했다.

HttpServletResponse를 사용해 적용하는 방법도 있다.

@PostMapping("/example")
public ResponseDto<YourData> createExample(HttpServletResponse response) {
    response.setStatus(HttpStatus.CREATED.value());
    return ResponseDto.created("생성 성공", data);
}

다만 이 방법은 HttpServletResponse를 파라미터에 추가해야 한다는 점이 마음에 들지 않아서 사용하지 않았다.

최종 결정

	@PostMapping("/signup")
    @ResponseStatus(HttpStatus.CREATED)
    public ResponseDto<ResPostSignUpDto> signUp(@RequestBody ReqPostSignUpDto requestDto) {

        ResPostSignUpDto resPostSignUpDto = ResPostSignUpDto.builder()
                .userId(UUID.randomUUID())
                .build();

        return ResponseDto.of("회원가입 성공", resPostSignUpDto);
    }

@ResponseStatus 어노테이션을 사용해 status를 지정하는 것으로 최종 결정했다. 기본 응답이 200 OK이고, 그 외의 status를 사용할 만한 일은 CREATED나 에러 핸들링을 하는 경우를 제외하고는 없다. 에러 핸들링은 @RestControllerAdvice를 통해 GlobalExceptionHandler를 구현해 사용할 것이므로 여기서는 넘어가고, 성공 시 응답만 고려해 CREATED가 필요한 부분은 어노테이션을 통해 처리할 수 있도록 했다.

공통 응답 DTO는 다음과 같이 수정했다.

@Getter
@Builder
public class ResponseDto<T> {
    private String message;
    private T data;

    public static <T> ResponseDto<T> of(String message, T data) {
        return ResponseDto.<T>builder()
                .message(message)
                .data(data)
                .build();
    }
}
profile
백엔드를 잘 하고 싶은 사람

0개의 댓글