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: 200 응답이 아닌 경우 에러코드 함께 반환 #98

Merged
merged 5 commits into from
Nov 16, 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
@@ -1,5 +1,6 @@
package com.nexters.goalpanzi.application.auth.apple;

import com.nexters.goalpanzi.exception.ErrorCode;
import com.nexters.goalpanzi.exception.UnauthorizedException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
Expand Down Expand Up @@ -43,7 +44,7 @@ private PublicKey generatePublicKeyWithApplePublicKey(final ApplePublicKey apple
KeyFactory keyFactory = KeyFactory.getInstance(applePublicKey.kty());
return keyFactory.generatePublic(publicKeySpec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException exception) {
throw new UnauthorizedException("응답 받은 Apple Public Key로 PublicKey를 생성할 수 없습니다.");
throw new UnauthorizedException(ErrorCode.CAN_NOT_CREATE_PUBLIC_KEY);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.nexters.goalpanzi.application.auth.apple;

import com.nexters.goalpanzi.exception.ErrorCode;
import com.nexters.goalpanzi.exception.UnauthorizedException;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
Expand All @@ -20,6 +21,6 @@ public ApplePublicKey getMatchesKey(final String alg, final String kid) {
.stream()
.filter(k -> k.alg().equals(alg) && k.kid().equals(kid))
.findFirst()
.orElseThrow(() -> new UnauthorizedException("Apple JWT 값의 alg, kid 정보가 올바르지 않습니다."));
.orElseThrow(() -> new UnauthorizedException(ErrorCode.INVALID_APPLE_TOKEN_FORMAT));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ private Mission getMissionByCode(final InvitationCode invitationCode) {
private void validateAlreadyJoin(final Member member, final Mission mission) {
missionMemberRepository.findByMemberIdAndMissionId(member.getId(), mission.getId())
.ifPresent(missionMember -> {
throw new AlreadyExistsException(ErrorCode.ALREADY_EXISTS_MISSION_MEMBER.toString());
throw new AlreadyExistsException(ErrorCode.ALREADY_EXISTS_MISSION_MEMBER);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,20 @@ public class MissionValidator {

public void validateJoinableMission(final InvitationCode invitationCode) {
Mission mission = missionRepository.findByInvitationCode(invitationCode)
.orElseThrow(() -> new NotFoundException(ErrorCode.NOT_FOUND_MISSION.toString()));
.orElseThrow(() -> new NotFoundException(ErrorCode.NOT_FOUND_MISSION));
validateMissionPeriod(mission);
validateMaxPersonnel(mission);
}

public void validateMaxPersonnel(final Mission mission) {
if (getMissionMemberSize(mission.getId()) > MAX_MISSION_MEMBER) {
throw new BadRequestException(ErrorCode.EXCEED_MAX_PERSONNEL.toString());
throw new BadRequestException(ErrorCode.EXCEED_MAX_PERSONNEL);
}
}

public void validateMissionPeriod(final Mission mission) {
if (mission.isMissionPeriod() || mission.isExpired()) {
throw new BadRequestException(ErrorCode.CAN_NOT_JOIN_MISSION.toString());
throw new BadRequestException(ErrorCode.CAN_NOT_JOIN_MISSION);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.nexters.goalpanzi.domain.mission.DayOfWeek;
import com.nexters.goalpanzi.domain.mission.Mission;
import com.nexters.goalpanzi.domain.mission.MissionStatus;
import com.nexters.goalpanzi.domain.mission.TimeOfDay;
import io.swagger.v3.oas.annotations.media.Schema;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private void respondWithUnauthorized(final HttpServletResponse response) throws
response.setContentType(CONTENT_TYPE);
response.setCharacterEncoding("UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(
new ErrorResponse(HttpStatus.UNAUTHORIZED.value(), ErrorCode.INVALID_TOKEN.getMessage()))
new ErrorResponse(HttpStatus.UNAUTHORIZED.value(), ErrorCode.INVALID_TOKEN.getMessage(), ErrorCode.UNAUTHORIZED))
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.nexters.goalpanzi.domain.mission;

import com.nexters.goalpanzi.exception.BadRequestException;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.AccessLevel;
Expand Down Expand Up @@ -44,7 +45,7 @@ private static String generateRandomCode() {

private void validate() {
if (!StringUtils.hasText(code) || this.code.length() != CODE_LENGTH) {
throw new IllegalArgumentException(INVALID_INVITATION_CODE.getMessage());
throw new BadRequestException(INVALID_INVITATION_CODE);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.nexters.goalpanzi.domain.common.BaseEntity;
import com.nexters.goalpanzi.domain.member.Member;
import com.nexters.goalpanzi.exception.BadRequestException;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
Expand Down Expand Up @@ -62,7 +63,7 @@ public MissionMember(final Member member, final Mission mission, final Integer v

public static MissionMember join(final Member member, final Mission mission) {
if (mission.isMissionPeriod()) {
throw new IllegalArgumentException(CAN_NOT_JOIN_MISSION.toString());
throw new BadRequestException(CAN_NOT_JOIN_MISSION);
}
return new MissionMember(member, mission, 0);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.nexters.goalpanzi.domain.mission;

import com.nexters.goalpanzi.exception.BadRequestException;
import com.nexters.goalpanzi.exception.BaseException;
import lombok.Getter;

import java.time.LocalDateTime;
Expand Down Expand Up @@ -61,6 +63,6 @@ public static MissionStatus fromMission(
return COMPLETED;
}

throw new IllegalArgumentException(UNKNOWN_MISSION.getMessage(mission, missionMember));
throw new BaseException(UNKNOWN_MISSION, mission.getId(), missionMember.getMember().getId());
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.nexters.goalpanzi.domain.mission;

import com.nexters.goalpanzi.exception.BadRequestException;
import lombok.Getter;

import java.util.Arrays;
Expand All @@ -25,6 +26,6 @@ public static TimeOfDay of(final String startTime, final String endTime) {
return Arrays.stream(TimeOfDay.values())
.filter(timeOfDay -> timeOfDay.startTime.equals(startTime) && timeOfDay.endTime.equals(endTime))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(INVALID_UPLOAD_TIME_OF_DAY.getMessage()));
.orElseThrow(() -> new BadRequestException(INVALID_UPLOAD_TIME_OF_DAY));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,4 @@ public AlreadyExistsException(final ErrorCode errorCode, final Object... args) {
super(errorCode, args);
}

public AlreadyExistsException(final String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@
public class BadRequestException extends BaseException {

public BadRequestException(final ErrorCode errorCode) {
super(errorCode.getMessage());
super(errorCode);
}

public BadRequestException(final ErrorCode errorCode, final Object... args) {
super(errorCode, args);
}

public BadRequestException(final String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
package com.nexters.goalpanzi.exception;

import lombok.Getter;

@Getter
public class BaseException extends RuntimeException {

private final ErrorCode errorCode;

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

public BaseException(final ErrorCode errorCode, final Object... args) {
super(errorCode.getMessage(args));
this.errorCode = errorCode;
}

public BaseException(final String message) {
super(message);
public BaseException(final ErrorCode errorCode, final Exception e) {
super(errorCode.getMessage(e));
this.errorCode = errorCode;
}
}
12 changes: 10 additions & 2 deletions src/main/java/com/nexters/goalpanzi/exception/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,17 @@
@AllArgsConstructor
@Getter
public enum ErrorCode {
// AUTH
// GENERAL
INTERNAL_SERVER_ERROR("일시적인 오류가 발생했습니다. 잠시 후 다시 시도해주세요."),
BAD_REQUEST("잘못된 요청입니다."),
UNAUTHORIZED("권한이 없습니다."),
RESOURCE_NOT_FOUND("리소스를 찾을 수 없습니다."),

// OAUTH
INVALID_APPLE_TOKEN("애플 토큰 검증에 실패하였습니다."),
EXPIRED_APPLE_TOKEN("애플 토큰이 만료되었습니다."),
CAN_NOT_CREATE_PUBLIC_KEY("응답 받은 Apple Public Key로 PublicKey를 생성할 수 없습니다."),
INVALID_APPLE_TOKEN_FORMAT("Apple JWT 값의 alg, kid 정보가 올바르지 않습니다."),

INVALID_TOKEN("서버 토큰 검증에 실패하였습니다."),
INVALID_REFRESH_TOKEN("refresh 토큰이 갱신되어 더 이상 유효하지 않은 refresh 토큰입니다."),
Expand All @@ -25,7 +33,7 @@ public enum ErrorCode {
INVALID_INVITATION_CODE("초대코드가 올바르지 않습니다."),
INVALID_UPLOAD_TIME_OF_DAY("올바르지 않은 미션 인증 업로드 시간대입니다."),
CANNOT_DELETE_MISSION("미션 삭제 권한이 없습니다."),
UNKNOWN_MISSION("정의되지 않은 미션상태입니다."),
UNKNOWN_MISSION("정의되지 않은 미션상태입니다. [missionId=%s, memberId=%s]"),

// MISSION MEMBER
ALREADY_EXISTS_MISSION_MEMBER("이미 참여한 미션입니다. [%s]"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.nexters.goalpanzi.exception;

public record ErrorResponse(
Integer code,
String message
Integer status,
String message,
ErrorCode errorCode
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
public class ForbiddenException extends BaseException {

public ForbiddenException(final ErrorCode errorCode) {
super(errorCode.getMessage());
}

public ForbiddenException(final String message) {
super(message);
super(errorCode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ protected ResponseEntity<Object> handleHandlerMethodValidationException(
WebRequest request) {

return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage()));
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage(), ErrorCode.BAD_REQUEST));
}

@Override
Expand All @@ -38,7 +38,7 @@ protected ResponseEntity<Object> handleMethodArgumentNotValid(
logger.error("message", ex);

return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage()));
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage(), ErrorCode.BAD_REQUEST));
}

@Override
Expand All @@ -50,7 +50,7 @@ protected ResponseEntity<Object> handleHttpMessageNotReadable(
logger.error("message", ex);

return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage()));
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage(), ErrorCode.BAD_REQUEST));
}

@Override
Expand All @@ -62,54 +62,71 @@ protected ResponseEntity<Object> handleMissingServletRequestParameter(
logger.error("message", ex);

return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage()));
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage(), ErrorCode.BAD_REQUEST));
}

@ExceptionHandler({UnauthorizedException.class})
public ResponseEntity<ErrorResponse> handleUnauthorizedException(final RuntimeException exception) {
public ResponseEntity<ErrorResponse> handleUnauthorizedException(final UnauthorizedException exception) {
logger.error("message", exception);

return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(new ErrorResponse(HttpStatus.UNAUTHORIZED.value(), exception.getMessage()));
.body(new ErrorResponse(HttpStatus.UNAUTHORIZED.value(), exception.getMessage(), exception.getErrorCode()));
}

@ExceptionHandler({BadRequestException.class, IllegalArgumentException.class})
public ResponseEntity<ErrorResponse> handleBadRequestException(final RuntimeException exception) {
@ExceptionHandler({IllegalArgumentException.class})
public ResponseEntity<ErrorResponse> handleIllegalArgumentException(final IllegalArgumentException exception) {
logger.error("message", exception);

return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), exception.getMessage()));
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), exception.getMessage(), ErrorCode.BAD_REQUEST));
}

@ExceptionHandler({NoSuchElementException.class, NotFoundException.class})
public ResponseEntity<ErrorResponse> handleNotFoundException(final RuntimeException exception) {
@ExceptionHandler({BadRequestException.class})
public ResponseEntity<ErrorResponse> handleBadRequestException(final BadRequestException exception) {
logger.error("message", exception);

return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(HttpStatus.BAD_REQUEST.value(), exception.getMessage(), exception.getErrorCode()));
}

@ExceptionHandler({NoSuchElementException.class})
public ResponseEntity<ErrorResponse> handleNoSuchElementException(final RuntimeException exception) {
logger.error("message", exception);

return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(HttpStatus.NOT_FOUND.value(), exception.getMessage()));
.body(new ErrorResponse(HttpStatus.NOT_FOUND.value(), exception.getMessage(), ErrorCode.RESOURCE_NOT_FOUND));
}

@ExceptionHandler({NotFoundException.class})
public ResponseEntity<ErrorResponse> handleNotFoundException(final NotFoundException exception) {
logger.error("message", exception);

return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(HttpStatus.NOT_FOUND.value(), exception.getMessage(), exception.getErrorCode()));
}


@ExceptionHandler(AlreadyExistsException.class)
public ResponseEntity<ErrorResponse> handleDuplicateException(final AlreadyExistsException exception) {
logger.error("message", exception);

return ResponseEntity.status(HttpStatus.CONFLICT)
.body(new ErrorResponse(HttpStatus.CONFLICT.value(), exception.getMessage()));
.body(new ErrorResponse(HttpStatus.CONFLICT.value(), exception.getMessage(), exception.getErrorCode()));
}

@ExceptionHandler({ForbiddenException.class})
public ResponseEntity<ErrorResponse> handleForbiddenException(final RuntimeException exception) {
public ResponseEntity<ErrorResponse> handleForbiddenException(final ForbiddenException exception) {
logger.error("message", exception);

return ResponseEntity.status(HttpStatus.FORBIDDEN)
.body(new ErrorResponse(HttpStatus.FORBIDDEN.value(), exception.getMessage()));
.body(new ErrorResponse(HttpStatus.FORBIDDEN.value(), exception.getMessage(), exception.getErrorCode()));
}

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleException(final Exception exception) {
logger.error("message", exception);

return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), exception.getMessage()));
.body(new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), exception.getMessage(), ErrorCode.INTERNAL_SERVER_ERROR));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@
public class NotFoundException extends BaseException {

public NotFoundException(final ErrorCode errorCode) {
super(errorCode.getMessage());
super(errorCode);
}

public NotFoundException(final ErrorCode errorCode, final Object... args) {
super(errorCode.getMessage(args));
}

public NotFoundException(final String message) {
super(message);
super(errorCode, errorCode.getMessage(args));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
public class UnauthorizedException extends BaseException {

public UnauthorizedException(final ErrorCode errorCode) {
super(errorCode.getMessage());
}

public UnauthorizedException(final String message) {
super(message);
super(errorCode);
}
}
Loading
Loading