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

[REFACTOR] 관리되지 않은 API 에러 분기 처리 개선 (UnhandledError) #408

Merged
merged 8 commits into from
Dec 3, 2024

Conversation

rbgksqkr
Copy link
Contributor

@rbgksqkr rbgksqkr commented Nov 20, 2024

Issue Number

#407

As-Is

  • 관리되지 않은 에러가 네트워크 에러로 처리되고 있었음

To-Be

  • UnhandledError 클래스를 만들어 네트워크 에러와 분기처리

Check List

  • 테스트가 전부 통과되었나요?
  • 모든 commit이 push 되었나요?
  • merge할 branch를 확인했나요?
  • Assignee를 지정했나요?
  • Label을 지정했나요?

Test Screenshot

에러 분기 처리 개선

기존에는 CustomError가 아니면 NetworkError를 throw 하게 했었는데, 관리되지 않는 에러도 처리하기 위해 분기처리를 추가하였습니다.
CORS에러 때문에 해당 이슈를 제기했는데, TypeError 클래스에 CORS에러가 포함되어 있어 브라우저의 navigator.onLine을 사용해 처리하였습니다. 이 또한 모바일에서 한번 더 확인해야하지만, 쿠키 정책으로 인해 머지 후 확인하겠습니다!

   try {
       ...
    } catch (error) {
      if (error instanceof TypeError && !navigator.onLine) {
        throw new NetworkError();
      }

      if (error instanceof CustomError) {
        throw error;
      }

      throw new UnhandledError();
    }

UnhandledError UI 처리

처리되지 않은 에러를 어떤 UI에서 처리할지 고민했는데 Toast, Modal, ErrorFallback 중 ErrorFallback을 선택하였습니다. 처리되지 않았다면 단순한 에러도 아니고, 사용자가 해결할 수 있는 문제도 아니여서 ErrorFallback을 보여주고 에러를 Sentry로 수집하도록 구현하였습니다.

CORS 에러 네트워크 에러
image image

(Optional) Additional Description

🌸 Storybook 배포 주소

https://woowacourse-teams.github.io/2024-ddangkong/storybook/

@rbgksqkr rbgksqkr added ♻️ refactor 리팩토링 🫧 FE front end labels Nov 20, 2024
@rbgksqkr rbgksqkr requested review from useon and novice0840 November 20, 2024 05:14
@rbgksqkr rbgksqkr self-assigned this Nov 20, 2024
@rbgksqkr rbgksqkr linked an issue Nov 20, 2024 that may be closed by this pull request
1 task
Copy link
Contributor

@novice0840 novice0840 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR 확인했습니다. 여러 경우에도 항상 에러 처리가 가능하도록 바뀌었군요 굿굿

Comment on lines 28 to 36
show(error.message);
return;
}

if (error instanceof UnhandledError) {
return;
}

showModal(AlertModal, { title: '에러', message: error.message });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙏 제안 🙏

함수 이름 형식을 맞추는 게 좋다고 생각하는데 show을 showToast로 바꾸는 건 어떠한가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 그것도 좋을 것 같네용

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

흠 근데 모달도 똑같이 show로 되어 있긴한데, showModal로 바꿀까요?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이미 showModal로 되어있는게 아닌가요?
{show: showModal}
{show: showToast} 를 생각하고 제안한 방식이긴 합니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗 사용할 때를 말한거였나요???
근데 항상 그렇게 사용할거면 그냥 함수 이름 자체를 바꾸는게 좋다고 생각해서 모달 띄우는 함수는 showModal, 토스트 띄우는 함수는 showToast로 수정하였습니다!

Comment on lines 29 to 32
if (error instanceof TypeError && !navigator.onLine) {
throw new NetworkError();
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 질문 💭

네트워크 에러 발생 시 항상 TypeError가 발생한다는 조건문인 것 같은데 네트워크 에러면서 TypeError는 아닌 경우가 있을 수도 있지 않을까요?

Copy link
Contributor Author

@rbgksqkr rbgksqkr Nov 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어떤 경우가 있을까요?? (진짜 궁금)

일단 fail to fetch 는 TypeError입니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

근데 그냥 !navigator.onLine 조건문만 달아도 될 것 같긴 하네용

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 로직과는 상관이 없지만 검색하다가 알게된 사실을 공유드려용
navigator.onLine이 false면 오프라인 상태라고 가정할 수 있지만, true가 반환되었다고 해서 반드시 브라우저가 인터넷에 액세스할 수 있다는 의미는 아니라고 합니다.

네트워크 어댑터와의 연결은 되었지만 실제 인터넷이 되는지는 판단할 수 없다고 합니다.
예를 들어 공용 와이파이 추가 로그인이나 제한된 인터넷 상태에서 true로 반환될 수 있다고 하네용

So while you can assume that the browser is offline when it returns a false value, you cannot assume that a true value necessarily means that the browser can access the internet.

image

https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine

Copy link
Contributor

@novice0840 novice0840 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

피드백 확인했습니다! Approve 할게요

@github-actions github-actions bot added D-3 3일 안에 리뷰 부탁드려요:) D-2 2일 안에 리뷰 부탁드려요:) and removed D-3 3일 안에 리뷰 부탁드려요:) labels Dec 3, 2024
Copy link
Contributor

@useon useon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

말우 리뷰가 늦어져서 미안합니다 😭unhandledError도 다룰 수 있도록 처리를 하는 모습 정말 좋네요 .. ^ .^ 애니메이션 깎기에 이어 에러 깎기까지 .. 그냥 궁금한 점에 대해서만 코멘트 달았으니 바로 어프루브 합니다 !!!!

@@ -22,7 +21,7 @@ const AsyncErrorFallback = ({ error, resetError }: AsyncErrorFallback) => {
return (
<section css={errorFallbackLayout}>
<img src={ErrorDdangkong} alt="에러나서 슬픈 땅콩" css={errorImage} />
<h2 css={errorText}>{error instanceof CustomError && error.message}</h2>
<h2 css={errorText}>{error instanceof Error && error.message}</h2>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 질문 💭

그럼 여기서 원래는 CustumError만 잡았는데 이제는 Error로 더 넓게 잡는건가요 .. ?

Copy link
Contributor Author

@rbgksqkr rbgksqkr Dec 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

음 사실 정확히는 error instanceof CustomError || error instanceof UnhandledError 로 잡는 게 맞는데 message만 사용하기도 하고, 한줄로 표현하고 싶어서 Error로 잡았던 것 같아요!

근데 썬데이말듣고 생각해보니 나중에 헷갈릴 수도 있을 것 같네용
error instanceof CustomError || error instanceof UnhandledError 로 명확하게 표현하겠습니다!

@@ -26,6 +28,11 @@ const QueryClientDefaultOptionProvider = ({ children }: PropsWithChildren) => {
show(error.message);
return;
}

if (error instanceof UnhandledError) {
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 질문 💭

해당 분기가 없으면 unhandledError도 모달이 뜨기 때문에 처리를 해 준 건가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 맞습니당

@github-actions github-actions bot added D-1 1일 안에 리뷰 부탁드려요:) D-0 이제 그냥 머지합니다? and removed D-2 2일 안에 리뷰 부탁드려요:) D-1 1일 안에 리뷰 부탁드려요:) labels Dec 3, 2024
@rbgksqkr rbgksqkr removed the D-0 이제 그냥 머지합니다? label Dec 3, 2024
@github-actions github-actions bot added the D-3 3일 안에 리뷰 부탁드려요:) label Dec 3, 2024
@rbgksqkr rbgksqkr merged commit 7572b19 into develop Dec 3, 2024
2 checks passed
@GIVEN53 GIVEN53 deleted the refactor/#407 branch December 10, 2024 11:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
D-3 3일 안에 리뷰 부탁드려요:) 🫧 FE front end ♻️ refactor 리팩토링
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

[REFACTOR] 관리되지 않은 API 에러 분기 처리 개선
3 participants