Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

에러 핸들링 어떻게 할 것인가 #343

Open
2 tasks
leegwae opened this issue Aug 15, 2023 · 0 comments
Open
2 tasks

에러 핸들링 어떻게 할 것인가 #343

leegwae opened this issue Aug 15, 2023 · 0 comments
Assignees
Labels
📝 documentation 문서 작성

Comments

@leegwae
Copy link
Member

leegwae commented Aug 15, 2023

클라이언트에서 발생할 수 있는 오류는 여러 가지가 있지만 우선은 fetch API를 사용하다 발생하는 오류를 중점으로 살피겠다.

현재 API 요청은 어떻게 다루고 있는가

현재 fetch API를 사용하여 API를 요청하고 있다. 성공 응답이 아니면 모두 Error 클래스를 상속받은 ApiError 클래스로 감싸고 throw하고 있다.

async function handleResponse<T>(response: Response): Promise<T> {
const data: Promise<T> = response.json();
if (response.ok) return data;
return Promise.reject(new ApiError(response, await data));
}
export async function request<T>(
method: string,
url: string,
options: RequestInit | undefined = {},
): Promise<T> {
const response = await fetch(url, { method, ...options });
return handleResponse(response);
}

어디서 API 요청하고 있는가

이 애플리케이션에서 현재까지 API 요청은

  1. React Router v6 loader
  2. React Query(쿼리의 경우, 컴포넌트 렌더링 중에 API 요청이 발생한다. 뮤테이션의 경우, 사이드 이펙트에서 API 요청이 발생한다.)

어떻게 API 에러 응답을 처리할 수 있는가

loader에서 발생하는 오류 처리하기

React Router loader의 경우, errorElement에서 처리할 수 있다. 이 errorElement는 React Router loader, action, 그리고 컴포넌트 렌더링에서 발생하는 오류를 핸들링할 수 있다. (확실하지 않음 컴포넌트 렌더링 중에 발생하는 오류는 핸들링할 수 있다. React Error Boundary 처럼 이벤트 핸들러와 비동기 콜백에서 발생하는 오류는 못 잡는다.)

쿼리에서 발생하는 오류 처리하기

세 가지가 있다. 첫번째, 렌더링 중에 error 프로퍼티 검사하여 fallback UI 반환하기

if (query.error) return <Fallback />

두번째, React Error Boundary 사용하여 선언적으로 처리하기 참고

<ErrorBoundary>
  <MyQueryComponent />
</ErrorBoundary>

세번째, onError 콜백에서 처리하기

useQuery({ onError: (error) => {} })

Error boundary는 이벤트 핸들러와 비동기 콜백에서 발생하는 오류는 못잡는다

세 가지 해결책이 있다.

  1. try...catch 문으로 해결한다.
  2. 그런 오류 잡아주는 라이브러리 사용한다. 예) react-error-boundary, @toss/error-boundary, 카카오 FE 블로그를 확인해봤는데 여기는 에러 발생하면 렌더링 도중에 에러를 발생시키는 거라 내가 원하는 건 아닌 거 같다.
  3. windowunhandledrejection 이벤트에다가 핸들러 등록한다

어떻게 할 것인가

일단 확인해야할 것들은 다음과 같다

  • React Router의 errorElement에서 error rethrow가 가능한지(여기서 못 잡으면 상위의 errorElement로 갈 수 있는지)
  • React Error boundary랑 React Router errorElement 같이 쓸 수 있는지(전자에서 rethrow한 거 후자가 잡을 수 있는지)

아래는 다음에 적을 것들

  • React Query 메인테이너가 제안한대로 백그라운드 refetch에서 실패했을 경우만 글로벌 onError로 토스트 메시지를 띄워주고 그 외에는 지역적으로 처리해도 괜찮아보인다
  • form validation처럼 에러 메시지를 띄워줄 곳이 마땅한 페이지를 제외하면 어떻게 일관성 있게 처리해줄 수 있을까? 모달이나 토스트를 띄워주는 게 좋은 경우와 Full Screen 페이지를 띄워주는 게 좋은 경우로 나눌 수 있을 거 같다.
  • loader에서 Response 에러만 throw하는 걸로 통일하자. 그러면 ApiError로 만들기 전 한 번 json으로 스트림 읽었으니까 다시 data로 새로운 Response 만들어서 내려주면 된다
  • React Router errorElement는 isRouteErrorResponse하고 loader에 명시적으로 throw한 에러만 조건문으로 fallback ui 놔주고 그 외에는 모조리 default fallback ui로 보여주면 될 거 같다.

대충 적는 시나리오

  1. loader에서 발생하는 오류는 react router errorElement에서 처리한다. isRouteErrorReponse이고 loader에서 명시적으로 throw한 에러라면 각각 fallback UI를 작성해준다. 처리 못한 에러는 알 수 없는 오류 새로고침하거나 홈 페이지 가세요 띄워준다 (그래서 상위로 보낼 수 있으면 제일 좋아보인다 root errorElement도 제일 마지막에 알 수 없는 오류 UI 넣어줄거라)
  2. 쿼리랑 뮤테이션에서 발생하는 오류는 비동기 지원해주는 Error boundary에서 잡던가, 아니면 throw해서 react router errorelement로 보내던가. 그런데 어떤 오류는 지역적으로 해결하고 싶고 어떤 경우는 아예 에러 바운더리로 올리고 싶은 경우라면 후자는 쓰지 말고 전자 쓰는 게 나아보인다. handler에서 발생하는 오류는 후자가 못 잡으니까 렌더링 중에 set 함수 호출하게 될 수도 있어서
    조심스럽다.
@leegwae leegwae added this to toquiz Aug 11, 2023
@leegwae leegwae self-assigned this Aug 15, 2023
@leegwae leegwae converted this from a draft issue Aug 15, 2023
@leegwae leegwae removed this from toquiz Aug 15, 2023
@leegwae leegwae added the 📝 documentation 문서 작성 label Aug 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
📝 documentation 문서 작성
Projects
None yet
Development

No branches or pull requests

1 participant