[Jersey] 3. WebApplicationException 상속 클래스를 이용한 Error Handling

2022. 5. 12. 14:12Spring/Jersey

반응형
  1. Error Handling 의 필요성
  2. 적용하기
    1. Response 클래스
    2. Exception처리 클래스 정의
    3. Service에 적용
  3. 결과
    1. 기본 제공 익셉션(WebApplicationException) 발생 시
    2. InvalidRequestException 발생 시

1. Error Handling 의 필요성

기존에 만들었던 API에서, 조회할 수 없는 사용자를 조회했을 때 아래와 아무런 응답이 나오지 않습니다.

Chrome DevTools를 열어보면, request는 실행되었다는 것을 확인할 수 있습니다.
저의 경우 204 HTTP status code와 함께 Response에 내용이 없이 도착했네요.

01-8


만일, 에러가 발생되었을 때 원하는 에러문구를 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로 설정되면서 아래와 같은 웹문서 형태로 출력되는 것을 확인할 수 있습니다.

01-9


REST Client로 확인해보면 보다 명확합니다.
동일하게 Content-Type이 text/html 이면서, body에 html문서가 출력된것을 확인할 수 있습니다.

01-10


3.2. InvalidRequestException 발생 시

존재하지 않는 user인 2222를 마찬가지로 조회 시도해봅니다.
400 코드와 함께 아래와 같은 응답화면이 출력됩니다.
Content-Type이 application/json 으로 출력되는 것을 확인할 수 있습니다.

{
    "result":"조회되는 User가 없습니다.",
    "reason":"FAIL"
}

01-11


REST Client 에서도 동일하게 출력됩니다.

01-12


※ GitHub에서 jersey 프로젝트(v1.0.2)를 다운받아 볼 수 있습니다.


++

  • How to customize error handling in jersey project
  • Exception Handling in JAX-RS REST APIs
728x90
반응형