에러 응답을 쉽고 간편하게 커스텀할 수 있는 problemDetails에 대해서 소개한다.
Problem Details는 Spring boot 3.0.x (Spring Framework 6.0.x)부터 사용가능하다.
Problem Details는 RFC 7807를 따른다.
RFC 7807 은 API 에러 응답에 대한 규약을 정의한 문서이다.
https://www.rfc-editor.org/rfc/rfc7807.html
RFC 7807 의 내용은 에러 발생 시 안내할 응답 내용을 문서 세부 정보 개체 ("type", "title", "status", "detail", "instance")와 확장 멤버로 구성하자는 것이다.
이 구성을 Problem Details는 그대로 따르고 있다.
https://github.com/spring-projects/spring-framework/blob/main/spring-web/src/main/java/org/springframework/http/ProblemDetail.java
ProblemDetail의 클래스의 구조는 깃허브에서 확인가능하다.
public class ProblemDetail {
private static final URI BLANK_TYPE = URI.create("about:blank");
// 문제 유형을 식별하는 URI 참조
private URI type = BLANK_TYPE;
// 문제 유형에 대한 사람이 읽을 수 있는 간단한 요약
@Nullable
private String title;
// 이 문제의 응답 Http status 코드
private int status;
// 문제 유형에 대한 사람이 읽을 수 있는 간단한 설명
@Nullable
private String detail;
// 문제가 발생한 URI
@Nullable
private URI instance;
// 위에 선언한 문서 세부 정보 필드 이외에 추가적으로 사용할 확장 필드를 저장하는 곳
@Nullable
private Map<String, Object> properties;
}
spring:
mvc:
problemdetails:
enabled: true
위처럼 true 값으로 설정해준다.
예외도 처리하고, 객체도 리턴해야해서 @RestControllerAdvice를 사용했다.
핸들러는 @ExceptionHandler() 를 사용해서 구현할 수 있다.
@RestControllerAdvice
public class ExceptionHandler {
@ExceptionHandler(UserNotExistsException.class)
public ProblemDetail handleUserNotExistsException(UserNotExistsException ex) {
ProblemDetail pd = ProblemDetail.forStatusAndDetail(
HttpStatus.NOT_FOUND, ex.getMessage());
pd.setTitle("존재하지 않는 유저입니다.");
pd.setProperty("timestamp", LocalDateTime.now());
pd.setProperty("message", message);
return pd;
}
status와 detail을 지정할 수 있다.
forStatus(), setDetail()로 따로 지정할 수도 있다.
타이틀을 지정한다.
추가적으로 확장필드를 지정할 수 있다.
타입을 지정한다.
인스턴스를 지정한다.

type은 따로 지정하지 않으면 기본값 "about:blank"가 출력된다.
title의 경우 따로 설정하지 않아도 HttpStatus의 값에 맞게 가져온다.
instance도 자동으로 에러가 발생한 uri를 가져온다.