Next.js 에서 Fetch를 활용해 커스텀 HTTP Client를 만들자(2)

MountionRiver·2024년 12월 9일

저번 글과 이어집니다.

저번에는 기본적인 HttpClient 만들기를했었다. 이어서 만들어보자

  1. 에러처리 통합하기

에러처리를 일관되게 받아보자

저번에 작성한 HttpClient를 보면 Response 설정 로직을 보면

 if (!response.ok) {
   const errorData = await response.json().catch(() => null); 
   throw new Error(
     errorData?.message ?? `HTTP error! status: ${response.status}`
   );
 }

가 있다.
이부분을 보면 response가 제대로 오지 않으면 에러를 던지는 구간이다. 그럼

throw new Error(
     errorData?.message ?? `HTTP error! status: ${response.status}`
   );

이 부분을 수정하면 에러를 일관되게 처리 할 수 있지 않을까?
그래서 에러를 일관되게 처리할 컴포넌트인 error.ts 파일을 만들고
new APIError(); 로 변경하자. 그리고 error.ts 파일을 작성해보자

// HttpClient.ts
const handleResponse = async <T>(response: Response, config: Config): Promise<T> => {
 if (!response.ok) {
   const errorData = await response.json().catch(() => null); 
   throw new new APIError();
 }

 const data = await response.json();
 return data as T;
};

이제 error.ts 파일을 작성해보자

내가 여기에 넣을 데이터는 총 4개이다.
1. 에러가 api에러인지 알려줄 것.
2. api 에러상태코드를 표기할 것.
3. api 보낼시 반환하는 에러 객체를 반환할 것.
4. 이전에 내가 보낸 데이터를 반환할 것.

이 네가지를 넣어야 한다.

커스텀 에러 클래스를 만든다.

이때 에러의 이름을 api 에러로 고정한다.

export class APIError extends Error {
   readonly name = "APIError"; 
}

생성자를 작성

export class APIError extends Error {
  readonly name = "APIError"; 

  public readonly originalMessage: any;
  constructor(
    public status: number,
    public data: any = null,
    message: any
    public readonly config?: any
  ) 

에러 정보를 구성한다.

  const errorInfo = {
      name: "APIError",
      status: status,
      message: message,
      data: data,
    };

super()를 통해 부모 클래스인 Error의 생성자를 호출

Error 생성자는 문자열 메시지를 받아야 하므로, errorInfo 객체를 JSON 문자열로 변환해야한다.
이렇게 하면 에러를 출력했을 때 아래와 같이 나온다.

{"name":"APIError","status":404,"message":"Not Found","data":null}

원본 메세지를 별도로 저장하고, 프로토 타입 체인을 재설정 해준다.

this.originalMessage = message //
Object.setPrototypeOf(this, APIError.prototype);

*프로토 타입 체인을 재설정하는 이유

  • JavaScript의 Error 객체는 내부적으로 this의 프로토타입을 Error.prototype으로 설정합니다.
    이로 인해 우리가 의도한 APIError.prototype으로의 연결이 끊어지고, 수동으로 프로토타입 체인을 잡을 필요가 있습니다.

JSON 변환 메서드 구현

  • Error 객체를 JSON.stringify()하면 대부분의 속성들이 누락됨.
  • Error 객체는 기본적으로 순환 참조를 포함할 수 있어 직렬화가 어려움
    -> toJSON 메서드를 구현함으로써 에러 객체를 JSON으로 변환할 때 필요한 모든 정보를 포함시킬 수 있다.
toJSON(): Record<string, unknown> {
  return {
    name: this.name,
    status: this.status,
    message: this.originalMessage,
    data: this.data,
  };
}

자이 이제 이렇게 만든걸 HttpClient 에 넣어주면 된다.

// HttpClient.ts
const handleResponse = async <T>(response: Response, config: Config): Promise<T> => {
 if (!response.ok) {
   const errorData = await response.json().catch(() => null); 
   throw new new APIError(
     response.status,
     config.body || null,
     errorData?.message || `Error ${response.status}`,
     config,);
 }

 const data = await response.json();
 return data as T;
};

0개의 댓글