문제상황:
프론트엔드와 백엔드 간에 서로 다른 형식의 응답 메시지가 전송되어 프론트엔드에서 응답을 올바르게 처리하지 못하는 문제가 발생했습니다.
해결방법:
응답 메시지 형식을 통일시켜 프론트엔드에서 일관된 방식으로 처리할 수 있도록 아래의 단계를 따라 해결하였습니다.
ApiResponse
클래스를 생성하였습니다. 이 클래스는 응답의 상태(status
), 메시지(message
), 데이터(data
)를 표현합니다.ApiResponse
클래스에는 성공(successData
, successMessage
)과 에러(error
) 응답을 생성하는 정적 메소드를 구현하여, 각각의 경우에 맞는 응답을 생성할 수 있도록 하였습니다. 이를 통해 응답을 좀 더 구체적으로 나타낼 수 있게 되었습니다.CustomException
클래스를 생성하여 각종 예외 사항에 대한 에러 코드(ErrrorCode
)를 정의하였습니다. 이렇게 함으로써, 예외 발생 시 해당 예외에 대한 상태 코드와 메시지를 일관되게 반환할 수 있게 되었습니다.GlobalExceptionHandler
클래스를 구현하였습니다. 이 클래스는 CustomException
을 처리하고, 해당 예외에 대한 응답을 ApiResponse
형식으로 생성하여 반환합니다. 이를 통해 예외가 발생하더라도 일관된 응답 메시지가 클라이언트에게 전달됩니다.이러한 방식으로 응답 메시지 형식을 통일시켜, 프론트엔드와 백엔드 간의 통신에서 발생하는 혼란을 해결하고, 클라이언트 측에서 응답을 올바르게 처리할 수 있게 되었습니다.
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ApiResponse<T> {
private static final String SUCCESS_STATUS = "success";
private static final String ERROR_STAUTS = "error";
private String status;
private String message;
private T data;
public ApiResponse(String status, String message, T data) {
this.status = status;
this.message = message;
this.data = data;
}
//성공
public static <T> ApiResponse<T> successData(T data) {
return new ApiResponse<>(SUCCESS_STATUS, null, data);
}
public static <T> ApiResponse<T> successMessage(String message) {
return new ApiResponse<>(SUCCESS_STATUS, message, null);
}
//에러
public static <T> ApiResponse<T> error(String message) {
return new ApiResponse<>(ERROR_STAUTS, message, null);
}
}
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler({CustomException.class})
public ResponseEntity<ApiResponse<?>> handleException(CustomException ex) {
return ResponseEntity.status(ex.getErrorCode().getHttpStatus())
.body(ApiResponse.error(ex.getErrorCode().getMessage()));
}
}
@Getter
@RequiredArgsConstructor
public class CustomException extends RuntimeException {
private final ErrrorCode errorCode;
}
@Getter
@RequiredArgsConstructor
public enum ErrrorCode {
INVALID_JWT_TOKEN(HttpStatus.UNAUTHORIZED, "유효하지 않은 토큰입니다."),
EXPIRED_JWT_TOKEN(HttpStatus.UNAUTHORIZED, "만료된 토큰 입니다."),
UNSUPPORTED_JWT_TOKEN(HttpStatus.UNAUTHORIZED, "지원되지 않는 토큰입니다."),
WRONG_JWT_TOKEN(HttpStatus.UNAUTHORIZED, "잘못된 토큰입니다."),
NOT_FOUND_ENTITY(HttpStatus.NOT_FOUND, "해당 데이터가 존재하지 않습니다."),
NOT_FOUND_POST(HttpStatus.NOT_FOUND, "해당 게시글이 존재하지 않습니다."),
NOT_FOUND_COMMENT(HttpStatus.NOT_FOUND, "해당 댓글이 존재하지 않습니다."),
NOT_AUTHORIZED(HttpStatus.UNAUTHORIZED, "권한이 없습니다."),
DUPLICATE_USERNAME(HttpStatus.CONFLICT, "이미 존재하는 아이디입니다."),
DUPLICATE_EMAIL(HttpStatus.CONFLICT, "이미 존재하는 이메일입니다."),
DUPLICATE_NICKNAME(HttpStatus.CONFLICT, "이미 존재하는 닉네임입니다.");
private final HttpStatus httpStatus;
private final String message;
}