Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] global response 추가 #13

Merged
merged 12 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.ourmenu.backend.global.exception;

public class CustomException extends RuntimeException {

private final ErrorCode errorCode;

public CustomException(String message, ErrorCode errorCode) {
super(message);
this.errorCode = errorCode;
}

public CustomException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.errorCode = errorCode;
}

public ErrorCode getErrorCode() {
return errorCode;
}
}
18 changes: 18 additions & 0 deletions src/main/java/com/ourmenu/backend/global/exception/ErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.ourmenu.backend.global.exception;

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@AllArgsConstructor
@Getter
public enum ErrorCode {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AllArgsConstructor@Getter 어노테이션을 사용한다면 코드가 간결해질 것 같아요


INTERNAL_SERVER(HttpStatus.INTERNAL_SERVER_ERROR, "G500", "서버 내부에서 에러가 발생하였습니다");

private final HttpStatus httpStatus;

private final String code;

private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.ourmenu.backend.global.exception;

import lombok.Builder;

@Builder
public record ErrorResponse(int status, String code, String message) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DTO에서 record 클래스를 사용하는 방법 좋은 것 같아요


public static ErrorResponse of(ErrorCode errorCode) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이와 같이 DTO에서 Response를 build하는 메소드를 정의해놓으면 Service 레이어의 코드가 간결해질 것 같네요! 👍👍

return ErrorResponse.builder()
.status(errorCode.getHttpStatus().value())
.code(errorCode.getCode())
.message(errorCode.getMessage())
.build();
}

public static ErrorResponse of(String message, ErrorCode errorCode) {
return ErrorResponse.builder()
.status(errorCode.getHttpStatus().value())
.code(errorCode.getCode())
.message(message)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.ourmenu.backend.global.exception;

import com.ourmenu.backend.global.response.ApiResponse;
import com.ourmenu.backend.global.response.util.ApiUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

@ExceptionHandler(RuntimeException.class)
public ApiResponse<?> handleException(RuntimeException e) {
return handleException(e, ErrorResponse.of(ErrorCode.INTERNAL_SERVER));
}

@ExceptionHandler(CustomException.class)
public ApiResponse<?> handleCustomException(CustomException e) {
return handleException(e, ErrorResponse.of(e.getMessage(), e.getErrorCode()));
}

public ApiResponse<?> handleException(Exception e, ErrorResponse errorResponse) {
log.error("{}: {}", errorResponse.code(), e.getMessage());
return ApiUtil.error(errorResponse);
}
}
17 changes: 17 additions & 0 deletions src/main/java/com/ourmenu/backend/global/response/ApiResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.ourmenu.backend.global.response;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.ourmenu.backend.global.exception.ErrorResponse;
import lombok.AllArgsConstructor;

@AllArgsConstructor
public class ApiResponse<T> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 @AllArgsConstructor 어노테이션을 사용할 수 있을 것 같아요


private final boolean isSuccess;

@JsonProperty(value = "response")
private final T response;

@JsonProperty(value = "errorResponse")
private final ErrorResponse errorResponse;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.ourmenu.backend.global.response.util;

import com.ourmenu.backend.global.exception.ErrorResponse;
import com.ourmenu.backend.global.response.ApiResponse;

public class ApiUtil {

private ApiUtil() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

정적 유틸리티 클래스 구조를 잘 구현해주신 것 같아요. 유틸 클래스는 객체지향적 프로그래밍이 아니라는 문제점이 있는데, 이에 대한 의견과 Spirng Bean으로 등록하는 방법에 대해 어떻게 생각하시는지 궁금합니다!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

정적 유틸 클래스는 분명 OOP를 벗어난 영역입니다. 구현하면서도 정적 클래스를 최대한 지양하는게 맞다고 생각했습니다. ApiUtil은 ApiResponse을 반환하는 역활을 가지고 있습니다. 분명 객체가 할 수 있는 영역입니다. 다만 진행하고 있는 프로젝트에서의 ApiUtil은 모든 엔드포인트 종단점에서 호출되어야하고. 만약 객체로 선언한다라면 메인 도메인 로직에서 불필요한 객체 선언을 계속 해야한다는 점에서 유틸클래스로 구현하게 되었어요.

}

public static <T> ApiResponse<T> success(T response) {
return new ApiResponse<>(true, response, null);
}

public static ApiResponse<?> error(ErrorResponse errorResponse) {
return new ApiResponse<>(false, null, errorResponse);
}
}