2022. 5. 12. 14:12ㆍSpring/Jersey
- Error Handling 의 필요성
- 적용하기
- 결과
1. Error Handling 의 필요성
기존에 만들었던 API에서, 조회할 수 없는 사용자를 조회했을 때 아래와 아무런 응답이 나오지 않습니다.
Chrome DevTools를 열어보면, request는 실행되었다는 것을 확인할 수 있습니다.
저의 경우 204 HTTP status code와 함께 Response에 내용이 없이 도착했네요.
만일, 에러가 발생되었을 때 원하는 에러문구를 Response Body에 출력하고 싶고, 또 HTTP status code도 내가 수정하고 싶다면 어떻게 해야할까요?
JAX-RS 구현체인 Jersey 프레임워크에서는 WebApplicationException를 상속받은 익셉션 클래스를 정의
하여 익셉션 발생시 보여줄 ResponseBody나 HTTP status code 등을 설정할 수 있습니다.
2. 적용하기
2.1. Response 클래스
먼저, 익셉션 발생에 이용될 ResponseBody에 이용될 클래스를 만듭니다.
api 응답 성공여부를 담는 result와 실패시 실패사유를 담을 reason 값을 갖고 있습니다.
package xyz.applebox.jersey.domain.value; import lombok.Getter; @Getter public class BaseResponse { private final String result; private final String reason; protected BaseResponse(){ this.result = "SUCCESS"; this.reason = ""; } private BaseResponse(String result){ this.reason = "FAIL"; this.result = result; } public static BaseResponse of() { return new BaseResponse(); } public static BaseResponse of(String result) { return new BaseResponse(result); } }
2.2. Exception처리 클래스 정의
JAX-RS에서는 api에서 HTTP 에러가 발생되었을 때 특정한 HTTP Response로 응답을 내보낼 수 있도록 도와 줍니다.
이에 관한 클래스는 WebApplicationException이고, 아래와 같은 하위클래스도 제공하고 있습니다.
※ 참고로 WebApplicationException의 기본 HTTP status code는 500 입니다.
code | class name |
---|---|
400 | BadReqeuustException |
401 | NotAuthhorizedException |
403 | ForbiddenException |
406 | NotAcceptableException |
404 | NotFoundException |
405 | NotAllowedException |
500 | InternalServerErrorException |
이번 포스팅에서는 익셉션클래스의 최상위 클래스인 WebApplicationException를 이용하여 익셉션 클래스를 새로 정의할 것입니다.
우리가 새로 생성할 익셉션 클래스인 InvalidRequestException 은, WebApplicationException 생성자를 호출하여 익셉션을 처리합니다.
public WebApplicationException(final Response response) { this((Throwable) null, response); }
JAX-RS Response 빌더에서 사용할 수 있는 메서드
- status: HTTP status code
- entity: response body
- type: Content-Type
package xyz.applebox.jersey.domain.exception; import xyz.applebox.jersey.domain.value.BaseResponse; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.io.Serial; public class InvalidRequestException extends WebApplicationException { @Serial private static final long serialVersionUID = -7267339423783060714L; public InvalidRequestException() { super(Response.status(Response.Status.BAD_REQUEST) .entity(BaseResponse.of("입력을 잘못했습니다.")) .type(MediaType.APPLICATION_JSON_TYPE).build()); } public InvalidRequestException(String msg) { super(Response.status(Response.Status.BAD_REQUEST).entity(BaseResponse.of(msg)).type(MediaType.APPLICATION_JSON_TYPE).build()); } }
HTTP status code는 400(BAD_REQUEST), 에러 문구를 담은 BaseResponse를 ResponseBody로, 그리고 Content-Type을 application/json
으로 설정했습니다.
2.3. Service에 적용
id를 이용하여 User를 조회하는 api에서, Optional<User> findById(Long id)
에서 Null인 경우에는 InvalidRequestException 을 발생시키도록 수정해봅니다.
@Transactional(readOnly = true) @RequiredArgsConstructor @Service public class UserService { private final UserRepository userRepository; public List<User> findAll() { return userRepository.findAll(); } public User findById(long id) { return userRepository.findById(id).orElseThrow(() -> new InvalidRequestException("조회되는 User가 없습니다.")); } }
3. 결과
3.1. 기본 제공 익셉션(WebApplicationException) 발생 시
직접 생성한 InvalidRequestException이 발생되었을 떄에 대한 화면을 보여주기 전에, 기본 WebApplicationException가 throws 되었을 때 어떻게 응답이 되는지 먼저 확인해봅니다.
웹 브라우저상에서 테스트를 해보면 Content-Type이 text/html
로 설정되면서 아래와 같은 웹문서 형태로 출력되는 것을 확인할 수 있습니다.
REST Client로 확인해보면 보다 명확합니다.
동일하게 Content-Type이 text/html
이면서, body에 html문서가 출력된것을 확인할 수 있습니다.
존재하지 않는 user인 2222를 마찬가지로 조회 시도해봅니다.
400 코드와 함께 아래와 같은 응답화면이 출력됩니다.
Content-Type이 application/json
으로 출력되는 것을 확인할 수 있습니다.
{ "result":"조회되는 User가 없습니다.", "reason":"FAIL" }
REST Client 에서도 동일하게 출력됩니다.
※ GitHub에서 jersey 프로젝트(v1.0.2)를 다운받아 볼 수 있습니다.
++
- How to customize error handling in jersey project
- Exception Handling in JAX-RS REST APIs
'Spring > Jersey' 카테고리의 다른 글
[Jersey] 6. CRUD API 생성 및 Validation 설정하기 (0) | 2022.05.16 |
---|---|
[Jersey] 5. ExceptionMapper를 이용한 전역 Error Handling (0) | 2022.05.13 |
[Jersey] 4. Response 전용 VO 이용하기 (0) | 2022.05.12 |
[Jersey] 2. JPA 및 datasource 설정하기 (0) | 2022.05.11 |
[Jersey] 1. Jersey 프로젝트 생성하기 (0) | 2022.05.10 |