Skip to content

♻️ (#483) ApiError + 에러 처리 로직 개선#494

Merged
daaoooy merged 13 commits intodevelopfrom
refactor/483-error
Mar 25, 2026
Merged

♻️ (#483) ApiError + 에러 처리 로직 개선#494
daaoooy merged 13 commits intodevelopfrom
refactor/483-error

Conversation

@daaoooy
Copy link
Copy Markdown
Contributor

@daaoooy daaoooy commented Mar 25, 2026

PR

🔍 한 줄 요약

  • ModalRenderer 위치 수정했습니다.
  • error 관련하여 구조 및 로직 개선했습니다.
  • 위 리팩터링 사항 일부 기능에 적용했습니다.



✨ 작업 내용

1. ModalRenderer 위치 수정했습니다.

  • 이전에 모달 렌더러를 라우터 밖에서 실행하도록 변경해버려서 서비스 내에서 모달 에러가 뜨는 상황이었습니다.
  • 이를 따로 RootLayout을 만들어 해결했습니다.
  • RootLayout은 가장 최상위 레이아웃으로 보시면 될 것 같습니다.

2. 에러 구조 개선

ApiError 고도화
  • 기존 코드는 message와 status를 직접 전달 받아 에러를 생성하는 구조였습니다.
  • 이를 AxiosError을 그대로 받아서 내부에서 필요한 정보를 추출하도록 구조를 변경했습니다.
  • 서버의 에러 응답 구조를 그대로 반영할 수 있도록 했습니다.
  • 서버에서 내려준 detail을 그대로 사용할 수 있도록 했습니다.
  • 에러를 몇 개 보니 아래 같은 형식으로 에러 응답이 와서 이걸 토대로 작업했습니다.
export interface ApiErrorResponse {
  type?: string;
  title?: string;
  status?: number;
  detail?: string;
  instance?: string;
  errors?: {
    field: string;
    message: string;
  }[];
}
ERROR_MAP 도입
  • 기존에는 에러 상수인 ERROR만 존재해서 특정 에러를 찾기 위해서는 직접 상수를 통해 접근해야만 했습니다.
  • 추가적으로 error.constants 에 ERROR_MAP을 추가하여 에러 타입만 알면 에러 정보를 조회할 수 있도록 했습니다.
  • 이 과정에서 ErrorItem, ErrorType 타입이 추가되었습니다. 상수 기반으로 타입을 자동 추출한 구조입니다.
에러 메세지 유틸 함수 구현
  • 에러 타입 기반으로 아래와 같은 우선순위를 가지는 에러 메세지 유틸 함수를 구현했습니다.
    1. error.type이 존재하고, ERROR_MAP에 정의되어있음 -> 프론트에서 정의한 표준 메세지 사용
    2. 없다면 error.errors를 확인해서 서버에서 내려주는 에러 메세지 사용
    3. 그래도 없으면 기본 메세지

3. 개선된 에러 구조와 처리 로직 일부 반영

  • error.response?.status 요렇게 귀찮게 쓰던 걸 error.status 같이 쓸 수 있습니다!!
  • 상수에 직접 정의하거나 서버의 에러 메세지를 그대로 사용하기 때문에 직접 에러 메세지를 토스트에 타이핑 할 필요가 없습니다!!
  • 모든 기능에 반영은 못 하였고, 생성, 삭제, 참여, 수정 등 위주로 반영해보았습니다.
axiosInstance
  • 기존에는 ApiError를 직접 생성할 때 message와 status를 수동으로 넘기는 형태였습니다.
  • 이를 AxiosError 객체를 ApiError에 전달하여 에러 파싱을 내부에서 일관되게 처리하도록 했습니다.
  • isAxiosError를 추가해서 Axios 에러가 아닌 경우는 먼저 분기하도록 했습니다.
  • 불필요하다고 판단한 async를 삭제했습니다. (await을 사용하는 로직이 없어보임)
각종 기능
  • 프로젝트, 할 일, 태그 CUD, 이름 변경, 회원 탈퇴 등 주요 기능에 우선 반영했습니다.
  • 기존에 catch를 사용해 단순히 에러를 보여주던 구조를 에러 상황에 맞는 구체적인 메세지를 사용자에게 제공하도록 했습니다.
  • mutation 내에서 UI 토스트를 처리하던 것을 삭제하고, 컴포넌트 혹은 훅에서 UI를 처리할 수 있도록 했습니다.
  • 다 유사한 형태로 리팩터링을 진행해서 혹시 질문이나 개선할 부분 있으시면 알려주세요.

4. 에러 관련된 모든 것을 shared > error 로 이동

  • types, constants, utils로 나누어 에러 관련 상수, 타입, 유틸을 위치시켰습니다.
  • 이곳저곳 있다보니 찾기가 어려워 한 곳에 두었습니다.

세부 상황 처리된 토스트 예시

이전 이후
image image



❗ 참고 사항

  • 일단 제목이 너무 길거나, 잘못된 참여 코드를 입력하거나, .. 이러한 세부 사항들에 대한 사용자 안내가 있어야 할 것 같아 급하게 추가해보았습니다.
  • 모든 기능에 추가되진 않아서 하나씩 살펴봐야할 것 같습니다.
  • 에러 구조 및 처리 로직은 함께 고민하고 명확하게 하는 것이 중요할 것 같아 많은 의견 부탁드립니다!
  • 해당 방식 채택되면 나머지 작업도 이어서 진행하겠습니다!



#️⃣ 연관 이슈

daaoooy added 11 commits March 26, 2026 00:40
- 에러 상수를 에러 타입 기반의 단층 구조로 변환하여 조회 효율 개선을 개선하기 위해 도입
- ApiError 클래스 개편에 따른 인터셉터 응답 로직 수정
- AxiosError 객체 기반의 자동 파싱 적용
- isAxiosError 가드를 추가하여 네트워크 외적 에러(JS 런타임 에러) 발생 시 Sentry 기록 및 원본 에러 전파
- mutation 내 toast 삭제하고 UI 처리는 컴포넌트에서 하도록 개선
- 개선한 ApiError 사용하여 리팩터링
- 상세 에러 정보가 토스트에 나타날 수 있도록 함
@daaoooy daaoooy requested a review from hyemomo March 25, 2026 16:15
@daaoooy daaoooy self-assigned this Mar 25, 2026
@daaoooy daaoooy added bug Something isn't working refactor 리팩터링 작업 labels Mar 25, 2026
@daaoooy daaoooy linked an issue Mar 25, 2026 that may be closed by this pull request
@daaoooy
Copy link
Copy Markdown
Contributor Author

daaoooy commented Mar 25, 2026

@github-actions
CI/CD Workflow / deploy-preview (pull_request) 가 실패해서 댓글 생성에 기능 임시로 추가해서 다시 푸시했습니당.. 근데도 안 되네영 빌드 쪽 문제는 아닌 듯 한데 ㅠㅠ Vercel 쪽에 뭐 뜨는 거 있나요? @hyemomo

@github-actions
Copy link
Copy Markdown

미리보기 배포 완료

배포 URL: https://team1-fe-wtyr-dork3nyi0-kimhyemins-projects.vercel.app
브랜치: refactor/483-error
커밋: d7bcc4d

@daaoooy
Copy link
Copy Markdown
Contributor Author

daaoooy commented Mar 25, 2026

@github-actions CI/CD Workflow / deploy-preview (pull_request) 가 실패해서 댓글 생성에 기능 임시로 추가해서 다시 푸시했습니당.. 근데도 안 되네영 빌드 쪽 문제는 아닌 듯 한데 ㅠㅠ Vercel 쪽에 뭐 뜨는 거 있나요? @hyemomo

오잉 해결됐습니다 일시적인 오류였나봐여

@daaoooy daaoooy mentioned this pull request Mar 25, 2026
5 tasks
Copy link
Copy Markdown
Collaborator

@hyemomo hyemomo left a comment

Choose a reason for hiding this comment

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

다연님! 실사용자 확보에 앞서 구체적인 에러 메시지를 제시해주는 건 확실히 필요할 것 같습니다. 구조는 저도 좀 익히면서 사용해봐야할 것 같네요! 수고하셨습니다!! 승인할게요!

Comment on lines +1 to +14
import { ERROR_MAP } from '@/shared/error/constants/error.constants';
import type { ApiError } from '@/shared/error/types/apiError.types';
import type { ErrorType } from '@/shared/error/types/error.types';

export const getErrorMessage = (error: ApiError) => {
const mapped =
error.type && error.type in ERROR_MAP ? ERROR_MAP[error.type as ErrorType] : undefined;

if (mapped) return mapped.detail;

if (error.errors?.length) return error.errors[0].message;

return error.detail ?? '요청에 실패했습니다.';
};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

오 여기서 메시지를 MAP에서 가져오거나 서버에서 내려두는 에러메시지를 사용하는 것이군요!👏🏻좋은 구조인 것 같아요!!! 감사합니당

Comment on lines 26 to +29
clearAuth();
return Promise.reject(new ApiError('UNAUTHORIZED', 401));

if (isAxiosError(error)) return Promise.reject(new ApiError(error));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

message와 status를 받아서 하는 것보다 에러를 그대로 받아서 내부에서 처리하는 게 확실히 역할도 분명해지겠네요! 👍🏻👍🏻

Comment on lines 68 to +73
{
path: '/',
element: <AppLayout />,
element: <RootLayout />,
errorElement: <RootFallback />,
children: PROTECTED_ROUTES.map((route) => ({
...route,
element: withProtected(route.element),
})),
children: [
...PUBLIC_ROUTES,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

확인했습니다!😊

@daaoooy daaoooy merged commit fc4dd3d into develop Mar 25, 2026
9 checks passed
@daaoooy daaoooy deleted the refactor/483-error branch March 26, 2026 00:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working refactor 리팩터링 작업

Projects

None yet

Development

Successfully merging this pull request may close these issues.

♻️ ApiError 구조 개선 ♻️ 할 일 관련 세부 에러 상황 처리

2 participants