본문 바로가기
Programming

Spring boot API ExceptionHandler

by BTC_동동 2023. 12. 22.

안녕하세요. 여러분 12월의 마지막이 다가오고 2023년의 마지막이자 2024년의 시작이 다가옵니다.

일단고 팀의 많은 글들이 도움이 되셨을지 궁금합니다.

그리고 이제 일단고 팀의 테크 블로그는 내년에도 볼 수 있을지.. ㅠㅠ

 

 

오늘 기술적인 부분을 마지막으로 업로드해볼까 합니다.

얼마전 API를 개발하고 사용하면서 예기치 못한 에러가 발생했습니다. 초보 개발자인 저는 깜짝 놀랐는데요. 특정 상황에 대한 예외처리가 부족했고 client가 응답받기 위한 응답을 정의하지 않아 client가 적절히 처리하기 어려웠습니다.

그래서 오늘은 Spring boot에서 ExceptionHandler를 이용해

Controller나 service에서든 예외에 대한 적절한 대응하는 방법을 말하고자 합니다.

 

1. ExceptionHandler 사용이유

특정 API 엔드포인트에서 예외가 발생한다고 가정해봅시다. 이 예외는 데이터베이스 연결 실패로 인한 것일 수 있고, 이에 대한 적절한 응답을 클라이언트에게 전달하지 않으면 클라이언트는 어떤 문제가 발생했는지 이해할 수 없어요. 이런 경우에 ExceptionHandler를 사용하면 이 예외를 적절하게 처리하고, 클라이언트가 이해하기 쉬운 형태로 응답을 보낼 수 있어요.

코드를 분리한다는 점에서 관리하기도 용이하구요.

그러면, 이어서 코드 예시를 통해 실제로 ExceptionHandler를 구현하는 방법을 보여줄게요. Spring에서는 @RestControllerAdvice 어노테이션을 사용하여 전역적으로 예외를 처리할 수 있습니다.

이 어노테이션을 사용하면 특정 패키지나 클래스에서 발생하는 예외를 처리하고, 클라이언트에게 응답을 보낼 수 있어요.

 

 

2. ExceptionHandler 만들기

이해하기 쉽게 controller에서 @Vaild 애노테이션에 대해 예외 처리를 진행할까 합니다.

 

@RestControllerAdvice
@ResponseStatus(HttpStatus.OK)
public class ApiExceptionControllerAdvice extends ResponseEntityExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultModel handleMethodArgumentNotValidException(MethodArgumentNotValidException x) {
        ResultModel result = new ResultModel();
        result.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
        result.setMessage("유효하지 않은 파라메타 입니다.");
        return result;
    }
}

위 코드에서 전역적으로 이 handler 이용하기 위해서 @RestControllerAdvice 애노테이션을 사용하고 handler할 대상 예외를 지정합니다.

@RestController
public class UserController {

    @PostMapping("/users")
    public ResponseEntity<String> createUser(@Valid @RequestBody UserRequest userRequest) {
        // 유효성 검사 후 유저 생성 로직
        return ResponseEntity.ok("User created successfully");
    }
}

 

위와 같은 controller가 존재하고 UserRequest 객체를 @Valid 를 통해 검증하고자 합니다.

만약 유효하지 않다면 MethodArgumentNotValidException이 발생하게 되고 이 예외가 발생하면 정의한 ApiExceptionControllerAdvice 에서 처리하고 handleMethodArgumentNotValidException 생성한 응답값이 client 측으로 반환되게 됩니다.

이렇게 하면 발생가능한 예외를 미리 별도의 코드에서 정의하고 Controller나 Service에서는 추가적으로 코드를 작성하지 않아도 되어 코드가 깔끔해지고 오류에 대해 효과적으로 처리할 수 있습니다.

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR), @ResponseBody 이 애노테이션을 Advice에 전역적 혹은 특정 ExceptionHandler에 적용해서 http 응답을 커스텀 한다면 client에게 오류에 대한 더 적절한 응답을 보낼 수 있을 것 같습니다.

저는 위와 같은 방법으로 예외에 대처해서 프런트에서 사용자가 어떤 오류를 맞이했는지 적절히 보여줄 수 있도록 처리하니 고객이 만족해 합니다.(어쩌면 당연해야 합니다 ㅠㅠ)

역시 초보 개발자이다 보니 많은 것을 알게 되고 중요한 것을 이제야 하나씩 배워가고 있습니다.

 

3. ExceptionHandler 활용(log insert)

저는 이제 예외에 대한 적절한 응답을 생성했지만 실제로 별도의 분석을 위해서 추가적으로 DB에 Error 로그를 insert 하려고 합니다.

Error가 발생했을 때 그 로그를 Controller나 Service에서 insert하려면 소스가 깔끔해지지 않는 경우가 있기 때문에 ExceptionHandler를 정의했다면 Error로그를 insert할 수 있게 바로 사용해도 좋을 것 같습니다.

 

일단 간단하게 예제 코드를 보여드린다면

public class ApiExceptionControllerAdvice extends ResponseEntityExceptionHandler {

	private final CommonPortalService commonPortalService;

	public ApiExceptionControllerAdvice(CommonPortalService commonPortalService) {
		this.commonPortalService = commonPortalService;
	}
		@ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultModel handleMethodArgumentNotValidException(HttpServletRequest request, MethodArgumentNotValidException x) {
        ResultModel result = new ResultModel();
				
				commonPortalService.insertApiUseErrorLog(request, x)

        result.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
        result.setMessage("유효하지 않은 파라메타 입니다.");
        return result;
    }
}

위에서 생성한 ApiExceptionControllerAdvice에 Error log만을 저장하기 위한 Service를 생성해주고 가져옵니다.

handler에 api 요청 http에 대한 정보도 받을 수 있도록 구성하고 http 정보와 예외 내용을 저장할 수 있도록 넘겨주고 처리한다면 예외에 대한 적절한 응답처리와 동시에 에러로그를 DB에 저장하고 분석하는 기능이 별도로 존재하게 되면서 코드 관리가 더 편해지게 됩니다.

 

마치며

저는 짧은 시간에 크고 작은 프로젝트를 계속 진행하면서 Java나 Vue, DB에 대해 많이 배웠습니다. 초보라서 그런지 누군가에게 당연한 것들이 저에게는 소중한 배움이 되어서 기분이 좋고 동시에 미리 알았더라면 하는 아쉬움도 남게 되네요 ㅎㅎ 그 중 하나가 ExceptionHandler입니다.

여러분의 2023년은 어떠셨나요? 저는 개인적으로 너무 소중한 해가 되었습니다. 좋은 배움과 좋은 사람과 함께 할 수 있어 좋았습니다. 일단고 팀의 테크 지식을 다루는 내용은 거의 마지막에 다와갑니다.

마지막 테크블로그 주제는 초보개발자로 프로젝트를 3개 정도 현업에서 진행했는데 초보개발자 입장에서 프로젝트를 돌아보면서 스스로 회고를 가지는 내용으로 2023년 테크블로그를 마무리해볼까 합니다.

회고의 내용을 통해 저와 같은 초보개발자가 있다면 미리 알고 미리 적용해볼 수 있는 기회가 되지 않을까요?!!!

여러분 모두 해피 메리 크리스마스

 

'Programming' 카테고리의 다른 글

LLM 이란?  (1) 2024.01.05
[MyBatis] Collection과 Association  (0) 2023.12.22
[개발] Django CSV 내보내기 액션 추가  (0) 2023.12.11
[BigData] VectorDB에 대하여  (1) 2023.12.08
백엔드 응답모델(result) 구성하기  (2) 2023.12.08

댓글