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] 표준 응답객체 구현 및 표준 에러 정의 #7

Merged
merged 5 commits into from
Oct 7, 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
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ dependencies {
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

// validation
implementation 'org.springframework.boot:spring-boot-starter-validation'
}

tasks.named('test') {
Expand Down
69 changes: 69 additions & 0 deletions src/main/java/com/leets/team2/xclone/common/ApiData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.leets.team2.xclone.common;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.leets.team2.xclone.exception.ErrorInfo;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.Builder;
import lombok.Getter;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;

@JsonSerialize
@Builder
@Getter
public class ApiData<T> {

private Boolean success;
private T data;
private Integer errorCode;
private Object errorMessage;

public static <T> ResponseEntity<ApiData<T>> successFrom(HttpStatus httpStatus, T data) {
ApiData<T> apiData = ApiData.<T>builder()
.success(true)
.data(data)
.build();
return ResponseEntity.status(httpStatus).body(apiData);
}

public static <T> ResponseEntity<ApiData<T>> ok(T data) {
ApiData<T> apiData = ApiData.<T>builder()
.success(true)
.data(data)
.build();
return ResponseEntity.ok(apiData);
}

public static <T> ResponseEntity<ApiData<T>> created(T data) {
ApiData<T> apiData = ApiData.<T>builder()
.success(true)
.data(data)
.build();
return ResponseEntity.status(HttpStatus.CREATED).body(apiData);
}

public static <T> ResponseEntity<ApiData<T>> validationFailure(List<FieldError> fieldErrors) {
Map<String, String> errors = new HashMap<>();
fieldErrors.forEach(
fieldError -> errors.put(fieldError.getField(), fieldError.getDefaultMessage()));

ApiData<T> apiData = ApiData.<T>builder()
.success(false)
.errorCode(ErrorInfo.NOT_VALID_REQUEST.getCode())
.errorMessage(errors)
.build();
return ResponseEntity.ok(apiData);
}

public static ResponseEntity<ApiData<String>> errorFrom(ErrorInfo error) {
ApiData<String> apiData = ApiData.<String>builder()
.success(false)
.errorCode(error.getCode())
.errorMessage(error.getMessage())
.build();
return ResponseEntity.status(error.getStatusCode()).body(apiData);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.leets.team2.xclone.exception;

import lombok.Getter;

@Getter
public class ApplicationException extends RuntimeException {

protected ErrorInfo errorInfo;

protected ApplicationException(ErrorInfo errorInfo) {
super(errorInfo.getMessage());
this.errorInfo = errorInfo;
}
}
20 changes: 20 additions & 0 deletions src/main/java/com/leets/team2/xclone/exception/ErrorInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.leets.team2.xclone.exception;

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

@Getter
@AllArgsConstructor
public enum ErrorInfo {

// validation 실패
NOT_VALID_REQUEST(HttpStatus.BAD_REQUEST, "요청을 검증하는데 실패했습니다.", 9999),

// Member 영역
NO_SUCH_MEMBER(HttpStatus.NOT_FOUND, "해당 멤버를 찾을 수 없습니다.", 10001);

private final HttpStatus statusCode;
private final String message;
private final int code;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.leets.team2.xclone.exception.handler;

import com.leets.team2.xclone.common.ApiData;
import com.leets.team2.xclone.exception.ApplicationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

private static final String INTERNAL_SERVER_ERROR = "서버에 오류가 발생했습니다.\n잠시후 다시 시도해주세요.";

@ExceptionHandler(ApplicationException.class)
public ResponseEntity<ApiData<String>> handleApplicationException(ApplicationException e) {
return ApiData.errorFrom(e.getErrorInfo());
}

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(RuntimeException.class)
public String handleAnyRunTimeException(RuntimeException e) {
log.warn("Unexpected Error Occurred", e);
return INTERNAL_SERVER_ERROR;
}



@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public String handleAnyCheckedException(Exception e) {
log.error("Unexpected Error Occurred", e);
return INTERNAL_SERVER_ERROR;
}

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiData<String>> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
return ApiData.validationFailure(e.getFieldErrors());
}
}
Loading