Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- Transactions Propagation Option
- 도커 컨테이너 로그
- 도커 로그 확인
- 자바버그수정
- @Builder @NoArgsConstructor
- spring JPA DB Connection
- repository annotation
- vueslot
- 도커 logs
- spring DB Connection
- Vue
- doker logs tail
- docker 로그
- spring repository
- JPA DB Connection 다중
- NoArgsConstructor
- AllArgsConstructor
- spring mapper annotation
- Spring JPA Specification
- spring JPA DB multi Connection
- mapper annotationo
- JpaRepository update
- JPA DB 다중 Connection
- Data Annotation
- Spring
- spring mapper
- CrudRepository update
- JAVA Exception 종류
- vuecomponent
- spring @mapper
Archives
- Today
- Total
개발을 잘하고 싶은 개발자
[Spring] RESTful 서비스 설계 - Exception 설계한 Response 처리 본문
api 호출이 항상 성공하지 않는다.
여러 예외도 있을뿐더러 설계 시 당연히 예외 처리는 필요하다.
List 형식의 데이터를 그냥 무작정 리턴해버리면 -> 그다음 받아서 처리할 때(Request -> Response)
성공해서 고대로 출력할 땐 문제가 되진 않지만
이 외의 케이스에서는 어떤 문제를 일으킬지 모르다!!
https://cheese10yun.github.io/spring-guide-exception/
Spring Guide - Exception 전략 - Yun Blog | 기술 블로그
Spring Guide - Exception 전략 - Yun Blog | 기술 블로그
cheese10yun.github.io
위 글을 보면서 많이 배우고 정리해보았다.
(내가 위에 횡설수설하게 적어 놓은 걸 아래와 같이 깔끔하게 써주셨다)
Error Response 객체는 항상 동일한 Error Response를 가져야 합니다. 그렇지 않으면 클라이언트에서 예외 처리를 항상 동일한 로직으로 처리하기 어렵습니다
Error Response JSON
{
"message": " Invalid Input Value",
"status": 400,
// "errors":[], 비어있을 경우 null 이 아닌 빈 배열을 응답한다.
"errors": [
{
"field": "name.last",
"value": "",
"reason": "must not be empty"
},
{
"field": "name.first",
"value": "",
"reason": "must not be empty"
}
],
"code": "C001"
}
- message : 에러에 대한 message를 작성합니다.
- status : http status code를 작성합니다. header 정보에도 포함된 정보이니 굳이 추가하지 않아도 됩니다.
- errors : 요청 값에 대한 field, value, reason 작성합니다. 일반적으로 @Valid 어노테이션으로 JSR 303: Bean Validation에 대한 검증을 진행합니다.
- 만약 errors에 바인인 된 결과가 없을 경우 null이 아니라 빈 배열 []을 응답해줍니다. null 객체는 절대 리턴하지 않습니다. null이 의미하는 것이 애매합니다.
- code : 에러에 할당되는 유니크한 코드값입니다.
Error Response 객체
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ErrorResponse {
private String message;
private int status;
private List<FieldError> errors;
private String code;
...
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public static class FieldError {
private String field;
private String value;
private String reason;
...
}
}
위 @Getter로 errorResponse.getStatus(); 형식으로 명확하게 객체의 값을 가져올 수 있다
이 글의 핵심은 바로 @ControllerAdvice과 @ExceptionHandler , @BusinessException어노테이션이다
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* javax.validation.Valid or @Validated 으로 binding error 발생시 발생한다.
* HttpMessageConverter 에서 등록한 HttpMessageConverter binding 못할경우 발생
* 주로 @RequestBody, @RequestPart 어노테이션에서 발생
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
protected ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error("handleMethodArgumentNotValidException", e);
final ErrorResponse response = ErrorResponse.of(ErrorCode.INVALID_INPUT_VALUE, e.getBindingResult());
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
/**
* @ModelAttribut 으로 binding error 발생시 BindException 발생한다.
* ref https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-modelattrib-method-args
*/
@ExceptionHandler(BindException.class)
protected ResponseEntity<ErrorResponse> handleBindException(BindException e) {
log.error("handleBindException", e);
final ErrorResponse response = ErrorResponse.of(ErrorCode.INVALID_INPUT_VALUE, e.getBindingResult());
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(BusinessException.class)
protected ResponseEntity<ErrorResponse> handleBusinessException(final BusinessException e) {
log.error("handleEntityNotFoundException", e);
final ErrorCode errorCode = e.getErrorCode();
final ErrorResponse response = ErrorResponse.of(errorCode);
return new ResponseEntity<>(response, HttpStatus.valueOf(errorCode.getStatus()));
}
@ExceptionHandler(Exception.class)
protected ResponseEntity<ErrorResponse> handleException(Exception e) {
log.error("handleEntityNotFoundException", e);
final ErrorResponse response = ErrorResponse.of(ErrorCode.INTERNAL_SERVER_ERROR);
return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
}
...
}
}
다음으로 위에서 많이 쓰는 "ErrorCode"는 ENUM으로 미리 선언해두고 쓰는 게 좋다
ublic enum ErrorCode {
// Common
INVALID_INPUT_VALUE(400, "C001", " Invalid Input Value"),
METHOD_NOT_ALLOWED(405, "C002", " Invalid Input Value"),
....
HANDLE_ACCESS_DENIED(403, "C006", "Access is Denied"),
// Member
EMAIL_DUPLICATION(400, "M001", "Email is Duplication"),
LOGIN_INPUT_INVALID(400, "M002", "Login input is invalid"),
;
private final String code;
private final String message;
private int status;
ErrorCode(final int status, final String code, final String message) {
this.status = status;
this.message = message;
this.code = code;
}
}
가독성이 아주 좋게 Exception을 사용한 예시가 있다
public class DeviceController {
...
public void sendShutDown() {
try {
tryToShutDown();
} catch (DeviceShutDownError e) {
logger.log(e);
}
}
private void tryToShutDown() throws DeviceShutDownError {
DeviceHandle handle = getHandle(DEV1);
DeviceRecord record = retrieveDeviceRecord(handle);
pauseDevice(handle);
clearDeviceWorkQueue(handle);
closeDevice(handle);
}
private DeviceHandle getHandle(DeviceID id) {
...
throw new DeviceShutDownError("Invalid handle for: " + id.toString());
...
}
...
}
이렇게 좋은 소스 보면서 눈 정화하고 가세요 ㅎㅎ

'Backend > spring' 카테고리의 다른 글
[Spring] JPA DB Connection 다중으로 사용하기! (0) | 2021.08.03 |
---|---|
[Spring JPA] JpaRepository update업데이트 하고 싶지만 save (0) | 2021.08.02 |
[Spring] DTO, VO, ENTITY 차이를 알고 써보자 (0) | 2021.07.22 |
[Spring JPA] PROCEDURE 프로시져 호출 (0) | 2021.07.17 |
servelt-mapping error Cannot resolve Servlet... (0) | 2016.01.28 |