refersh token을 도입하기 이전에는 security filter에서 발생할 오류가 인증되지 않은 오류 뿐이었으나, 이제는 토큰이 만료되었는지, 비정상적인 접근이 감지되었는지, 서버에 저장된 키 값과 불일치하는지 등 오류 개수가 점차 많아졌습니다.
대부분이 토큰 관련 오류인데, 토큰 관련 응답을 프론트에서 원하는 형태로 전달해주기 위해서는 기존 구조를 이용할 수 없었습니다. 기존 구조는
@Getter @AllArgsConstructor
public static class ApiResult<T> {
private final boolean success;
private final T response;
private final ApiError error;
}
@Getter @AllArgsConstructor
public static class ApiError {
private final String message;
private final int status;
}
이런 구조를 가지고 있었습니다. (레코드로 고쳐야 하는데, 아직 그대로 남아있네요) 아무튼! 프론트에서는 ApiError
부분에서 status
값을 문자열로 구분해서 전달받기를 원하고 있었습니다. 현재 구조로는 int
형만 전달 가능해서 코드를 수정해야 했습니다.
그래서 두가지 방법을 생각해 보았는데
TokenResult
, TokenError
)ErrorData
라는 상위 객체를 만들고, 이를 상속받는 ApiError
, TokenError
생성하기즉 상속구조를 이용할 것인지, 아니면 객체를 완벽히 분리시킬지를 고민했습니다. 제가 생각하기에, 기존의 객체는 API의 응답용 객체인데 토큰 관련 오류는 요청으로 들어온 응답도 물론 있지만(/user/token
) 대부분은 API 요청에 대한 권한과 유저 확인에서 발생하는 오류이기 때문에 형태는 동일하나 목적이 다릅니다.
따라서 이 경우에는 상속보다는 분리가 맞다고 생각했고, 이를 구현한 코드는
public record TokenResponse(
boolean success,
String response,
TokenError error
) {
public record TokenError(String code, String message) {}
public static TokenResponse error(TokenException tokenException) {
return new TokenResponse(
false,
null,
new TokenError(tokenException.getCode(), tokenException.getMessage())
);
}
}
이렇게 분리를 시켰습니다.
생각해보면, response와 error를 굳이 구분할 필요도 없을 것 같습니다. 기존 API 응답에서도 success 필드가 이미 존재하는데 굳이 error를 만드는 것도 객체의 책임이 하나가 아닌 둘이 되는 것 같습니다.
에러용 응답인지, 성공해서 나가는 응답인지를 구분하는 것이 옳다고 생각하는데, 현재 구조는 두 경우를 단 하나의 객체가 담당하고 있습니다. 처음부터 객체를 분리해서 설계하였다면, 지금과 같은 고민은 없었을 것 같습니다.