HTTP 상태 코드 종류를 잘 알아둬야할 필요가 있는데,
만약 모니터링을 하는 시스템을 만들었다 라고 하면, 서버가 돌아가면서 문제가 있는 상황에 알림을 주는 설정을 만들어 놓는 경우가 많이 있기 때문이다.
현재상황
- 클라이언트가 '중복되는 폴더명'을 작성해서 에러가 발생하는 상황. 클라이언트 잘못이기 때문에 4XX 오류가 나와야하는데 500 에러가 발생한다.
To Do
{
"errorMessage":"중복된 폴더명을 제거해 주세요! 폴더명: 신발",
"httpStatus":"BAD_REQUEST"
}
예외 처리 전
@PostMapping("api/folders")
public List<Folder> addFolders(
@RequestBody FolderRequestDto folderRequestDto,
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
List<String> folderNames = folderRequestDto.getFolderNames();
User user = userDetails.getUser();
return folderService.addFolders(folderNames, user);
}
@PostMapping("api/folders")
public ResponseEntity addFolders(
@RequestBody FolderRequestDto folderRequestDto,
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
try {
List<String> folderNames = folderRequestDto.getFolderNames();
User user = userDetails.getUser();
List<Folder> folders = folderService.addFolders(folderNames, user);
return new ResponseEntity(folders, HttpStatus.OK);
} catch (IllegalArgumentException ex) {
RestApiException restApiException = new RestApiException();
restApiException.setHttpStatus(HttpStatus.BAD_REQUEST);
restApiException.setErrorMessage(ex.getMessage());
return new ResponseEntity(
// HTTP body
restApiException,
// HTTP status code
HttpStatus.BAD_REQUEST);
}
}
@ExceptionHandler({IllegalArgumentException.class})
public ResponseEntity handleException(IllegalArgumentException ex) {
RestApiException restApiException = new RestApiException();
restApiException.setHttpStatus(HttpStatus.BAD_REQUEST);
restApiException.setErrorMessage(ex.getMessage());
return new ResponseEntity(
// HTTP body
restApiException,
// HTTP status code
HttpStatus.BAD_REQUEST
);
}
ControllerAdvice가 Controller인 척하면서 모든 try/catch를 처리해준다.
ControllerAdvice는 하나가 아닐 수 있고 여러 개로 처리할 수도 있다.
@RestControllerAdvice // 모든 Controller에 적용이 된다
public class RestApiExceptionHandler {
@ExceptionHandler(value = { IllegalArgumentException.class })
public ResponseEntity<Object> handleApiRequestException(IllegalArgumentException ex) {
RestApiException restApiException = new RestApiException();
restApiException.setHttpStatus(HttpStatus.BAD_REQUEST);
restApiException.setErrorMessage(ex.getMessage());
return new ResponseEntity(
restApiException,
HttpStatus.BAD_REQUEST
);
}
}
Exception이 발생했을 때 JSON 형태로 바디 부분에 해당하는 restApiException을 넘겨준다.
Global한 Exception을 할 때 ErrorCode를 선언해서 사용하는 경우도 많다.
서비스 전체에 사용할 에러코드들 (ErrorCode) 을 선언
예외발생 시 서버 및 클라이언트에서 선언한 ErrorCode 사용
에러코드 샘플
import org.springframework.http.HttpStatus;
import static com.sparta.springcore.service.ProductService.MIN_MY_PRICE;
public enum ErrorCode {
// 400 Bad Request
DUPLICATED_FOLDER_NAME(HttpStatus.BAD_REQUEST, "400_1", "중복폴더명이 이미 존재합니다."),
BELOW_MIN_MY_PRICE(HttpStatus.BAD_REQUEST, "400_2", "최저 희망가는 최소 " + MIN_MY_PRICE + " 원 이상으로 설정해 주세요."),
// 404 Not Found
NOT_FOUND_PRODUCT(HttpStatus.NOT_FOUND, "404_1", "해당 관심상품 아이디가 존재하지 않습니다."),
NOT_FOUND_FOLDER(HttpStatus.NOT_FOUND, "404_2", "해당 폴더 아이디가 존재하지 않습니다."),
;
private final HttpStatus httpStatus;
private final String errorCode;
private final String errorMessage;
ErrorCode(HttpStatus httpStatus, String errorCode, String errorMessage) {
this.httpStatus = httpStatus;
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}
}
전에 한번 본적 있던 예외처리 부분을 제대로 공부하게돼서 관심있게 공부하게 됐다.
다만 ErrorCode 활용 방법은 현업에서 많이 사용하기에 더 찾아봐서 적용해보고 익숙해져야될 필요가 있다고 생각한다.
5주차 강의를 마치면서 남기신 말씀
스프링도 그렇고, 프로그래밍도 그렇고 암기과목이 아니라는 것을 명심해라.
5주동안 다뤘던 내용들을 모두 다 암기하려고 노력하지 말아라.
한번 성공한 경험, 프로젝트를 돌려본 경험이 있다면, 나중에 구글링을 통해서 찾을 능력이 있다.
암기보다는 원리파악을 해놓으면 검색할 때 더 수월하다.