오봉이와 함께하는 개발 블로그
스프링 MVC 2 - API 예외 처리 : 시작 본문
API 예외 처리 - 시작
API 예외 처리는 어떻게 해야할까?
HTML 페이지의 경우 지금까지 설명했던 것 처럼 4xx, 5xx와 같은 오류 페이지만 있으면 대부분의 문제를 해결할 수 있다.
그런데 API의 경우에는 생각할 내용이 더 많다.
오류 페이지는 단순히 고객에게 오류 화면을 보여주고 끝이지만, API는 각 오류 상황에 맞는 오류 응답 스펙을 정하고, JSON으로 데이터를 내려주어야 한다.
지금부터 API의 경우 어떻게 예외 처리를 하면 좋은지 알아보자.
API도 오류 페이지에서 설명했던 것 처럼 처음으로 돌아가서 서블릿 오류 페이지 방식을 사용해보자.
WebServerCustomizer 다시 동작
WebServerCustomizer
가 다시 사용되도록 하기 위해 @Component
어노테이션에 있는 주석을 풀자 이제 WAS에 예외가 전달되거나, response.sendError()
가 호출되면 위에 등록한 예외 페이지 경로가 호출된다.
ApiExceptionController - API 예외 컨트롤러
@Slf4j
@RestController
public class ApiExceptionController {
@GetMapping("/api/members/{id}")
public MemberDto getMember(@PathVariable("id") String id) {
if (id.equals("ex")) {
throw new RuntimeException("잘못된 사용자");
}
return new MemberDto(id, "hello " + id);
}
@Data
@AllArgsConstructor
static class MemberDto {
private String memberId;
private String name;
}
}
예외 테스트를 위해 URL에 전달된 id의 값이 ex면 예외가 발생하도록 코드를 심어두었다.
Postman으로 테스트
HTTP Header에 Accept 가 application/json 인 것을 꼭 확인하자.
정상 호출http://localhost:8080/api/members/spring
{
"memberId": "spring",
"name": "hello spring"
}
예외 발생 호출http://localhost:8080/api/members/ex
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div class="container" style="max-width: 600px">
<div class="py-5 text-center">
<h2>500 오류 화면</h2>
</div>
<div>
<p>오류 화면 입니다.</p>
</div>
<hr class="my-4">
</div> <!-- /container -->
</body>
</html>
API를 요청했는데, 정상의 경우 API로 JSON 형식으로 데이터가 정상 반환된다.
그런데 오류가 발생하면 우리가 미리 만들어둔 오류 페이지 HTML이 반환된다.
이것은 우리가 기대하는 바가 아니다.
클라이언트는 정상 요청이든, 오류 요청이든 JSON이 반환되기를 기대한다.
브라우저가 아닌 이상 HTML을 직접 받아서 할 수 있는 것은 별로 없다.
문제를 해결하려면 오류 페이지 컨트롤러도 JSON 응답을 할 수 있도록 수정해야 한다.
ErrorPageController - API 응답 추가
@RequestMapping(value = "/error-page/500", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Map<String, Object>> errorPage600Api(HttpServletRequest request, HttpServletResponse response) {
log.info("API errorPage 500");
Map<String, Object> result = new HashMap<>();
Exception ex = (Exception) request.getAttribute(ERROR_EXCEPTION);
result.put("status", request.getAttribute(ERROR_STATUS_CODE));
result.put("message", ex.getMessage());
Integer statusCode = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
return new ResponseEntity<>(result, HttpStatus.valueOf(statusCode));
}
produces = MediaType.APPLICATION_JSON_VALUE
의 뜻은 클라이언트가 요청하는 HTTP Header의 Accept
의 값이 application/json
일 때 해당 메서드가 호출된다는 것이다.
결국 클라어인트가 받고 싶은 미디어타입이 json이면 이 컨트롤러의 메서드가 호출된다.
응답 데이터를 위해서 Map
을 만들고 status
, message
키에 값을 할당했다.
Jackson 라이브러리는 Map
을 JSON 구조로 변환할 수 있다.ResponseEntity
를 사용해서 응답하기 때문에 메시지 컨버터가 동작하면서 클라이언트에 JSON이 반환된다.
포스트맨을 통해서 다시 테스트 해보자.http://localhost:8080/api/members/ex
{
"message": "잘못된 사용자",
"status": 500
}
throw new RuntimeException("잘못된 사용자");
를 통해 메시지를 작성해 놓았다.RuntimeException
에러가 터지도록 했기 때문에 RuntimeException
이 발생하고, ErrorPage errorPageEx = new ErrorPage(RuntimeException.class, "/error-page/500");
에 따라서 컨트롤러에 매핑되어 있는 /error-page/500
이 호출되는데, 위 코드에 produces = MediaType.APPLICATION_JSON_VALUE
를 통해 더 자세하게 명시했기 때문에 해당 컨트롤러가 작동한다.
Map(result
)에 에러 메시지(잘못된 사용자
)와 status(500
)을 넣어놓고 return
값으로 넘겨 주었다.HttpStatus.valueOf(statusCode)
를 통해 Postman에 500에러를 준다.
HTTP Header에 Accept
가 application/json
이 아니면, 기존 오류 응답인 HTML 응답이 출력되는 것을 확인할 수 있다.
출처 : 인프런 김영한 지식공유자님 강의 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
'BE > Spring' 카테고리의 다른 글
스프링 MVC 2 - HandlerExceptionResolver 시작 (0) | 2022.08.31 |
---|---|
스프링 MVC 2 - 스프링 부트 기본 오류 처리 (0) | 2022.08.31 |
스프링 MVC 2 - 스프링 부트 : 오류 페이지 (0) | 2022.08.30 |
스프링 MVC 2 - 서블릿 예외 처리 : 인터셉터 (0) | 2022.08.30 |
스프링 MVC 2 - 서블릿 예외 처리 : 필터 (0) | 2022.08.30 |