티스토리 뷰
결과 메시지 설계
Error Message 구성
field | type |
Description |
---|---|---|
httpStatus | int |
결과 코드, 정상인 경우 200 |
errorMessage | String |
에러 메시지 |
detailMessage |
String |
에러 상세 메시지 |
HTTP 응답상태코드 (rfc2616 참고)
성공
실패
* 응답 상태 코드 중 사용할 만한 것만 선별한 것입니다.
참고 소스 (스프링 기반)
ErrorMessage.java
@Getter
@NoArgsConstructor
public class ErrorResponse {
private int httpStatus;
private String errorMessage;
private String detailMessage;
public ErrorResponse(int httpStatus, String errorMessage, String detailMessage) {
super();
this.httpStatus = httpStatus;
this.errorMessage = errorMessage;
this.detailMessage = detailMessage;
}
}
Test
@GetMapping("/api/users")
public ResponseEntity<List<User>> getUsers(User user) {
List<User> users = new ArrayList<>();
for(int i=0; i<10;i++) {
users.add(new User("user_"+i, "사용자_"+i, "facebook"));
}
return ResponseEntity.ok(users);
}
결과
- [
]
- {
},
- "userId":"user_0",
- "userPwd":null,
- "name":"사용자_0",
- "authType":"facebook"
- {
},
- "userId":"user_1",
- "userPwd":null,
- "name":"사용자_1",
- "authType":"facebook"
- {
},
- "userId":"user_2",
- "userPwd":null,
- "name":"사용자_2",
- "authType":"facebook"
- {
},
- "userId":"user_3",
- "userPwd":null,
- "name":"사용자_3",
- "authType":"facebook"
- {
},
- "userId":"user_4",
- "userPwd":null,
- "name":"사용자_4",
- "authType":"facebook"
- {
},
- "userId":"user_5",
- "userPwd":null,
- "name":"사용자_5",
- "authType":"facebook"
- {
},
- "userId":"user_6",
- "userPwd":null,
- "name":"사용자_6",
- "authType":"facebook"
- {
},
- "userId":"user_7",
- "userPwd":null,
- "name":"사용자_7",
- "authType":"facebook"
- {
},
- "userId":"user_8",
- "userPwd":null,
- "name":"사용자_8",
- "authType":"facebook"
- {
}
- "userId":"user_9",
- "userPwd":null,
- "name":"사용자_9",
- "authType":"facebook"
예외 생성(스프링 기반)
에러를 어떻게 처리할지를 먼저 결정하고 그에 따라 Exception을 설계합니다.
Exception 발생시 Respons status는 Exception에 정의한 HttpStatus를 활용할거며 에러 메시지와 HttpStatus의 value를 반환할 것입니다.
AbstractEbloBaseException.java
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
|
import org.springframework.http.HttpStatus;
public abstract class AbstractEbloBaseException extends RuntimeException {
private static final long serialVersionUID = 1L;
public AbstractEbloBaseException() {
super();
}
public AbstractEbloBaseException(String msg) {
super(msg);
}
public AbstractEbloBaseException(Throwable e) {
super(e);
}
public AbstractEbloBaseException(String errorMessge, Throwable e) {
super(errorMessge, e);
}
public abstract HttpStatus getHttpStatus();
}
|
cs |
EbloNotFoundException.java
not found exception
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
|
import org.springframework.http.HttpStatus;
public class EbloNotFoundException extends AbstractEbloBaseException {
private static final long serialVersionUID = 1L;
public EbloNotFoundException() {
super();
}
public EbloNotFoundException(Throwable e) {
super(e);
}
public EbloNotFoundException(String errorMessge) {
super(errorMessge);
}
public EbloNotFoundException(String errorMessge, Throwable e) {
super(errorMessge, e);
}
public HttpStatus getHttpStatus() {
return HttpStatus.NOT_FOUND;
}
}
|
cs |
EbloInvalidRequestException.java
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
|
import org.springframework.http.HttpStatus;
public class EbloInvalidRequestException extends AbstractEbloBaseException {
private static final long serialVersionUID = 1L;
public EbloInvalidRequestException() {
super();
}
public EbloInvalidRequestException(Throwable e) {
super(e);
}
public EbloInvalidRequestException(String errorMessge) {
super(errorMessge);
}
public EbloInvalidRequestException(String errorMessge, Throwable e) {
super(errorMessge, e);
}
public HttpStatus getHttpStatus() {
return HttpStatus.BAD_REQUEST;
}
}
|
cs |
이외 EbloForbiddenException, EbloUnauthorizedException, EbloUnknownException, EbloSystemException 등 공통 Exception 생성.
에러 코드는 스프링의 HttpStatus 이용합니다.
Exception 처리
스프링에서는 Controller based Exception Handling과 Global Exception Handling 두가지 형태로 처리 할 수 있습니다.
참고
Exception Handling in Spring MVC : https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
저는 서비스에 따라 각각 처리할 때 공통 컨트롤러를 만들고 그것을 상속 받아서 처리하게 만들었습니다.
AbstractBaseRestController. java
@RestControllerAdvice(basePackages = "eblo.example.common.api")
public class APIExceptionControllerAdvice {
@ExceptionHandler(AbstractEbloBaseException.class)
protected ResponseEntity<ErrorResponse> handleApiException(AbstractEbloBaseException e) {
return ResponseEntity
.status(e.getHttpStatus())
.body(
new ErrorResponse(
e.getHttpStatus().value(),
e.getHttpStatus().getReasonPhrase(),
e.getDetailMessage()
)
);
}
@ExceptionHandler(Exception.class)
protected ResponseEntity<ErrorResponse> exception(Exception e) {
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(
new ErrorResponse(
HttpStatus.INTERNAL_SERVER_ERROR.value(),
HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(),
e.getLocalizedMessage()
)
);
}
}
Rest 서비스에 대한 컨트롤러입니다.
각 서비스, 컨트롤러에서 예외를 던지면 @ExceptionHandler를 통해 예외를 자동 처리 해주게 됩니다.
예외에 따라 Response status를 결정하고 에러 코드와 메시지를 생성합니다.
이렇게 예외를 처리하게 되면 불필요한 코드를 다 제거 할 수 있게 되고 소스의 가독성 역시 엄청나게 향샹 됩니다.
* 이외 일반 컨트롤러에서 에러 발생시 에러 페이지로 연결하는 공통 컨트롤러를 만들어서 사용하게 되면 코딩이 한결 수월해 집니다.
컨트롤러 예제
UserAuthRestController.java
@RestController
@Slf4j
public class UserAuthRestController {
@GetMapping("/api/users")
public ResponseEntity<List<User>> getUsers(User user) {
Assert.notNull(user.getUserId(), "요청 사용자 id는 필수 입니다.");
List<User> users = new ArrayList<>();
for(int i=0; i<10;i++) {
users.add(new User("user_"+i, "사용자_"+i, "facebook"));
}
return ResponseEntity.ok(users);
}
}
마무리
REST 서비스에서 사용하는 공통 MESSAGE와 EXCEPTION에 대한 예제를 만들어 보았습니다.
이중에 Exception은 매우 중요하다고 생각합니다. Rest 서비스가 아니더라도 exception 만큼은 잘 알고 코딩을 했으면 좋겠습니다.
고급 개발자 또는 잘하는 사람의 코딩을 보면 굉장히 간결하고 짧게 코딩이 되어 있는 것을 볼 수 있습니다.
코드를 간결하고 쉽게 만드는 비결 중 하나는 얼마만큼 exception을 다룰 수 있는가 하는 능력이라고 봅니다.
코드의 반은 try-catch이고 나머지 반은 조건문인 경우가 많습니다. 이런 부분만 해소하면 코드 품질이 엄청나게 향상될거라 생각합니다.
'Spring Frameworks > RESTful Service' 카테고리의 다른 글
RESTful 서비스 설계와 개발 - URI 설계 (0) | 2019.02.01 |
---|---|
RESTful 서비스 설계와 개발 - REST 소개와 기본 구성 (0) | 2019.01.31 |
RESTful 서비스 설계와 개발 - 변화된 서비스 환경 (0) | 2019.01.31 |
- Total
- Today
- Yesterday
- sample
- 예제
- lombok
- spring
- example
- cache
- 샘플
- 스프링부트
- 메시지
- mapToList
- 설정
- springboot
- 그리드
- thymeleaf
- UI
- restful서비스
- Javascript
- oracle
- REST
- SHEETJS
- 타임리프
- java
- mybatis
- 스프링
- AG-GRID
- Spring Boot
- listToMap
- ag grid
- 엑셀
- RESTful
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |