fetchWrapper로 에러 처리하기

임홍원·2024년 11월 27일
0

토이프로젝트를 진행하던 와중 공통 에러는 어떻게 처리할 것인가에 곰곰이 생각해보았다.
유튜브에서 해외 개발자 영상을 찾아보던 와중에 좋은 방법이 있어 기록하고자 한다.

현재 토이프로젝트는 React, refine을 사용중이다.

fetch를 한 곳에서만 하기

api를 호출할 때 fetch를 사용중이다.
만약 api를 호출할 때마다 fetch를 사용한다면 공통에러를 잡기가 쉽지않다.
그래서 fetch 요청을 한 군데에서만 처리하고 그곳에서 에러 처리를 하는것이 좋다.

fetchWrapper

공통에러처리를 위해 fetchWrapper로 만들어주었다.

import { GraphQLFormattedError } from "graphql";

type Error = {
	message: string;
	statusCode: string;
};

const customFetch = async (url: string, options: RequestInit) => {
	const accessToken = localStorage.getItem("access-token");
	const headers = options.headers as Record<string, string>;

	return await fetch(url, {
		...options,
		headers: {
			...headers,
			Authorization: headers?.Authorization || `Bearer ${accessToken}`,
			"Content-Type": "application/json",
			"Apollo-Require-Preflight": "true",
		},
	});
};

const getGraphQLErrors = (
	body: Record<"errors", GraphQLFormattedError[] | undefined>
): Error | null => {
	if (!body) {
		return {
			message: "Unknown error",
			statusCode: "INTERNAL_SERVER_ERROR",
		};
	}

	if ("errors" in body) {
		const errors = body?.errors;
		const messages = errors?.map((error) => error?.message)?.join("");
		const code = errors?.[0].extensions?.code;

		return {
			message: messages || JSON.stringify(errors),
			statusCode: code || 500,
		};
	}

	return null;
};

export const fetchWrapper = async (url: string, options: RequestInit) => {
	const response = await customFetch(url, options);

	const responseClone = response.clone();
	const body = await responseClone.json();
	const error = getGraphQLErrors(body);

	if (error) {
		throw error;
	}

	return response;
};

fetch 를 한번에 처리하기위해 customFetch 함수를 만들어 안에서 accessToken 을 실어 fetch 를 진행한다.
현재 graphQL을 사용중이므로 에러를 잡아내기위해 getGraphQLErrors 함수를 만들어주었다.

body가 없는 경우와 errorsbody에 있는경우를 분기처리해준다. 만약 에러가 없다면 nullreturn 해준다.

fetchWrapper 안에서 작성한 customFetch를 사용해서 fetch 요청을 보내고 에러가 있을경우 throw 해준다.

만약 graphQL을 사용중이지 않고 REST API를 사용중이라면 아래와 같이 바꿀 수 있다.

const getRestErrors = (response: Response): Error | null => {
  if(!response.ok) {
    return {
    	message: `HTTP Error ${response.status}`,
      	statusCode: response.status.toString()
    };
  }
  
  return null;
}

이제 fetchWrapper를 사용해보자!

import { GraphQLClient } from "@refinedev/nestjs-query";
import { fetchWrapper } from "./fetch-wrapper";

export const API_URL = "https://api.crm.refine.dev";

export const client = new GraphQLClient(API_URL, {
	fetch: (url: string, options: RequestInit) => {
		try {
			return fetchWrapper(url, options);
		} catch (error) {
			return Promise.reject(error as Error);
		}
	},
});

0개의 댓글

관련 채용 정보