[TIL] 221113

먼지·2022년 11월 13일
0

TIL

목록 보기
42/57
post-thumbnail

문제

존재하지 않는 id의 게시글을 요청했을 때 어떻게 에러를 처리할 것인가..! 초반에 작성한 id에 해당하는 게시글(post)을 가져오는 api와 useQuery

// board/api.ts
export const getPostRequest = async (id: number): Promise<Post> => {
  try {
    return await (
      await fetch(`${BOARD_API_END_POINT}/read/${id}`, {
        method: 'GET',
        headers,
      })
    ).json();
  } catch (e) {
    throw new Error(`게시글 조회를 실패했습니다. ${e}`);
  }
};

// Post.tsx
export default function Post() {
  const navigate = useNavigate();
  const { id } = useParams<{ id: string }>();
  const { data: post } = useQuery(
    ['Post', id],
    () => getPostRequest(Number(id)),
    {
      refetchOnWindowFocus: false,
      onSuccess: (res) => {
        console.log('onSuccess:', res);
      },
      onError: (err) => {
        console.log('onError:', err);
      },
    }
  );

일단 내가 보통 기능 구현을 위주로 코드를 작성하는데 저 위의 api 코드에서 데이터를 제대로 받아오지 못하면 catch 문으로 빠지고 useQuery에서 가져오는 error 데이터와 onError option으로 에러가 넘어올 거라고 생각했는데 그렇지 않아서 나중에 생각하자.. 하고 계속 미뤘다.

구글링으로 react query error handling 등 여러 가지 글들을 읽었는데 보통은 error, onError 로 넘어온다는데, 내가 잘못된 요청을 했을 때 data 프로퍼티와, onSuccess 로

에러 정보가 담긴 객체가 오고 error로 안 빠지기 때문이다. 백엔드님께 원래 이렇게 오는 건지 여쭤보니 500 부분은 처리를 안 하신 것 같다고 해서 BAD_REQUEST를 리턴해주시겠다고 했다.

어쨌든 이것도 쿼리 요청이 성공했을 때 실행되는? 함수인 onSuccess로 데이터가 넘어오기 때문에 useQuery의 두 번째 인자인 json 데이터를 리턴하는 함수에서 따로 작업을 해야 할 것 같고, 대부분의 잘못된 요청에서 에러코드가 정해진 json 데이터가 오기 때문에 catch 문을 다 제거해야겠다..!

일단 getPostRequest 에서만 제거

export const getPostRequest = async (id: number): Promise<Post> => {
  return await (
    await fetch(`${BOARD_API_END_POINT}/read/${id}`, {
      method: 'GET',
      headers,
    })
  ).json();
};

catch 문 없이도 똑같이 데이터가 온다.

잘못된 요청

일단 잘못된 요청 부분의 에러를 어떻게 처리할지 생각!

try

return data에 errorCode가 존재하는지 확인하고 null을 리턴하려고 했는데, 정상 작동하지만 타입스크립트가 errorCode 속성을 읽지 못했다.

getPostRequest가 어떤 프로미스 데이터를 리턴하는지 적어봤는데도 아직 빨간줄,,

import { Post } from './type';

export const getPostRequest = async (
  id: number
): Promise<Post | { errorCode: string; message: string }> => {

api.ts 파일에다 반환되는 Promise 데이터에 errorCode가 있는지 확인 후 예외처리

export const getPostRequest = async (id: number): Promise<Post> => {
  const json = await (
    await fetch(`${BOARD_API_END_POINT}/read/${id}`, {
      method: 'GET',
      headers,
    })
  ).json();
  if (json.errorCode) throw new Error(json.message);
  else return json;
};

onError 와 error 프로퍼티에 에러 정보가 잘 도착?했다!

문제가 생겼을 때 데이터 요청이 여러 번 가는 것은 retry option으로 설정했고, error가 있으면 if 문으로 Error 컴포넌트를 반환하게 처리했다.

export default function Post() {
  const navigate = useNavigate();
  const { id } = useParams<{ id: string }>();
  const { data: post, error } = useQuery(['Post', id], () => getPostRequest(Number(id)), {
    retry: 1, // 임시
    ...
  });
    
  if (error) return <Error error={error} />;

  return (...);
}

throw vs throw Error vs throw new Error

throw 문은 사용자가 정의한 '예외'를 발생시킬 수 있다. '예외'가 발생하면 함수가 중지되고 catch문으로 전달된다. catch문이 없다면 프로그램이 종료된다.(참고)
추가 실행을 종료하고 오류를 잡을 때 메시지 문자열을 노출

stackoverflow - What is the difference between throw new Error and throw someObject?
영어가 너무 많아서 일단 살짝 읽고 대충 적어보자면

throw Error와 throw new Error는 비슷함.
throw new Error는 name & message 두 개의 프로퍼티가 있는 에러 객체 전달
throw Error는 Error가 생성자가 아닌 함수로 호출되면 새로운 Error 객체를 생성하고 초기화하는데 적절하지 않은 방법이지만 작동은 한다.

그래서 throw로 코드를 변경했는데 react query에서 에러로 빠졌고 Error 컴포넌트에서도 type이 string인 에러 메세지가 전달됐다. 근데 message props를 string type이라 작성하면 Post 컴포넌트 message에 빨간줄이 뜬다

// pages/Post.tsx
...
  if (error) return <Error message={error} />;
  
// components/Error.tsx
const Error = ({ message }: { message: string }) => {
  console.log(typeof message); // string
  return <div>{message}</div>;
};

export default Error;

ErrorBoundary랑 suspense 이것저것 찾아봐서 적용해 봤는데 상위 컴포넌트에 적용하는 거라 하위 컴포넌트 하나라도 문제가 생기면 다 fallback ui를 보여주는데 내가 생각한 방식이 아니었고 제대로 써본 적이 없어서 일단 각각 컴포넌트마다 error property로 에러를 처리하려고 한다.

전에도 react query를 사용했을 때 에러 처리를 이렇게 작성하긴 했는데, 나는 보통 기능 구현을 먼저 끝내는 걸 목표로 코드를 작성해서 항상 에러 처리를 뒷전으로 미뤄 제대로 공부하지 못했고 게다가 이번엔 넘어오는 에러 데이터가 달랐는데 당연히 error로 빠질거라 생각했기에 어디서부터 수정할지 간단하게 생각하지 못했다.

처음부터 완벽할 수 없는데 그런 마음으로 시작하려는 게 제일 큰 나의 문제점이다. 정말 잘 알고 있는데 아직까지 고쳐지지 않아서 내 코드가 창피해도 일단 조금씩 시도해서 발전시켜야겠다 😭

profile
꾸준히 자유롭게 즐겁게

0개의 댓글