우당탕탕 개발일지
[Spring] API 공통 응답 본문
스프링에서 API 응답 방식으로 보통 ResponseEntity 방식을 사용한다. ResponseEntity는 응답의 상태 코드와 데이터를 포함하지만, 각 API마다 응답 형식이 달라진다. API 공통 응답 구조는 API 개발 및 유지보수의 효율성을 높이며 클라이언트에게도 일관성 있는 응답을 전송하는 것은 중요하다.
API 공통 응답 패키지 구조는 다음과 같다.
common
├─constants
├─ ErrorCode
└─ SuccessCode
├─dto
├─ ApiErrorResponse
└─ ApiSuccessResponse
├─exceptions
├─ GeneralException
└─ GlobalExceptionHandler
└─utils
└─ CommonResponse
1. 응답 코드 작성
[ SuccessCode ]
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public enum SuccessCode {
SUCCESS_SIGNUP(HttpStatus.OK, "회원가입 성공"),
SUCCESS_SIGNIN(HttpStatus.OK, "로그인 성공"),
SUCCESS_TOKEN_REFRESH(HttpStatus.OK, "AccessToken 갱신 성공"),
SUCCESS_LOGOUT(HttpStatus.OK, "로그아웃 성공");
private final HttpStatus status;
private final String message;
}
[ ErrorCode ]
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public enum ErrorCode {
JWT_VERIFICATION(HttpStatus.UNAUTHORIZED, "토큰 검증에 실패하였습니다."),
INVALID_AUTH_TOKEN(HttpStatus.UNAUTHORIZED, "유효하지 않은 JWT 토큰입니다."),
INVALID_REFRESH_TOKEN(HttpStatus.UNAUTHORIZED, "유효하지 않은 Refresh 토큰입니다."),
BLACKLISTED_TOKEN(HttpStatus.UNAUTHORIZED, "이미 로그아웃된 계정입니다"),
USERNAME_ALREADY_EXIST(HttpStatus.CONFLICT, "이미 존재하는 계정입니다."),
USERNAME_NOT_FOUND(HttpStatus.NOT_FOUND, "해당하는 사용자 계정을 찾을 수 없습니다."),
USER_NOT_FOUND(HttpStatus.NOT_FOUND, "해당하는 사용자를 찾을 수 없습니다."),
PASSWORD_MISMATCH(HttpStatus.UNAUTHORIZED, "비밀번호가 일치하지 않습니다."),
INVALID_INPUT_VALUE(HttpStatus.BAD_REQUEST, "입력 값이 유효하지 않습니다."),
MISSING_REQUIRED_FIELD(HttpStatus.BAD_REQUEST, "필수 입력 필드가 누락되었습니다."),
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 에러입니다. 관리자에게 문의하세요.");
private final HttpStatus status;
private final String message;
}
API 요청이 성공했을 때와 실패했을 때 일관된 응답 형식을 제공하기 위한 Enum 클래스이다.
HTTP 상태 코드와 응답 메시지를 저장한다.
2. 기본 응답 형식 작성
[ CommonResponse ]
@Data
public class CommonResponse<T> {
private final Boolean success;
private final String message;
protected CommonResponse(Boolean success, String message) {
this.success = success;
this.message = message;
}
public static CommonResponse res(Boolean success, SuccessCode status) {
return new CommonResponse(success, status.getMessage());
}
}
성공 여부와 상태 코드 메시지를 포함한 기본적인 응답 구조를 제공한다. 특별한 데이터가 없는 경우 사용한다.
3. 에러 응답 작성
[ ApiErrorResponse ]
@Getter
public class ApiErrorResponse extends CommonResponse<String> {
private final HttpStatus status;
public ApiErrorResponse(String message, HttpStatus status) {
super(false, message);
this.status = status;
}
public static ApiErrorResponse res(String message, HttpStatus status) {
return new ApiErrorResponse(message, status);
}
}
API 요청이 실패했을때, HTTP 상태 코드와 에러 메시지를 반환한다.
4. 성공 응답 작성
[ ApiSuccessResponse ]
@Getter
public class ApiSuccessResponse<T> extends CommonResponse {
private final T data;
private ApiSuccessResponse(String message, T data) {
super(true, message);
this.data = data;
}
public static<T> ApiSuccessResponse<T> res(SuccessCode status, T data) {
return new ApiSuccessResponse<>(status.getMessage(), data);
}
}
API 요청이 성공했을때, 데이터를 반환한다.
5. 예외 처리 작성
[ GeneralException ]
@Getter
public class GeneralException extends RuntimeException{
private final ErrorCode errorCode;
public GeneralException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.errorCode = errorCode;
}
}
[ GlobalExceptionHandler ]
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(GeneralException.class)
public ApiErrorResponse handleGeneralException(GeneralException e) {
return new ApiErrorResponse(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(UsernameNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ApiErrorResponse handleUsernameNotFoundException(UsernameNotFoundException e) {
return new ApiErrorResponse(e.getMessage(), HttpStatus.NOT_FOUND);
}
@ExceptionHandler(BadCredentialsException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public ApiErrorResponse handleBadCredentialsException(BadCredentialsException e) {
return new ApiErrorResponse(e.getMessage(), HttpStatus.UNAUTHORIZED);
}
}
'Spring' 카테고리의 다른 글
[Spring] JUnit + Mockito 테스트 코드 작성 (3) | 2024.09.27 |
---|---|
[Spring] Redis를 활용한 토큰 관리 최적화 (2) | 2024.09.26 |
[Spring] Swagger - API 명세서 작성 (1) | 2024.09.15 |
[Spring] JWT 서비스 (0) | 2024.07.11 |
JPA - 데이터 모델링 (0) | 2024.05.20 |