따꿍의 프로젝트

[Sprint 3] API 호출 공통 래퍼 (Axios의 interceptor / Fetch Wrapper) 본문

웹프로젝트/코드잇

[Sprint 3] API 호출 공통 래퍼 (Axios의 interceptor / Fetch Wrapper)

공장 주인 따꿍 2026. 4. 15. 23:45

발단

try-catch-finally를 모든 API에 실행하고 싶지 않았다. 

그래서 이 처리를 한 곳에 하고 싶었는데

이게 현직에서도 사용되는 패턴인지 궁금했다. 

 

찾아보니 API 호출 공통 래퍼라고,

Axios는 interceptor로 처리하고,

Fetch는 직접 만든 Fetch Wrapper로 처리한다고 한다. 

 

내가 작성한 Fetch Wrapper

body가 가장 까다로웠다. 

    GET / POST / PATCH / PUT / DELETE 중에 
    GET은 body가 없어야하는데 
    body가 있는 경우에만 fetch options 객체에 body attribute를 추가하는 방법을 고안해 내는것이 어려웠다. 

- 근데 생각해보니 fetch에서 options (config로 이름 바꿈)을 따로 객체 형태로 꺼내고
    request method에 따라서 config.body를 추가하거나, 아니면 언급조차 안하거나 선택하면 됐다. 

export const BASE_URL = "https://panda-market-api-crud.vercel.app";
export default async function request(method = "GET", url, body, options = {}) {
  try {
    //1. fetch의 config와 필요하다면 body 세팅하기
    const config = {
      method,
      headers: {
        "Content-Type": "application/json",
      },
      ...options,
    };
    if (method !== "GET" && body) {
      //GET일 경우 body를 추가하지 않도록 함
      config.body = JSON.stringify(body);
    }

    //2. fetch로 요청하기
    const result = await fetch(`${BASE_URL}${url}`, config);
    const data = await result.json();

    //3. 에러 처리하기
    if (!result.ok) {
      //응답 상태 코드가 2XX 아닐시
      throw new Error(data?.message || "Request Failed");
    }
    return data;
  } catch (e) {
    console.error(e);
    throw e;
  }
}
import request from "./main.js";
const ARTICLE_URL = "/articles";

export const getArticleList = async (page, pageSize, keyword) => {
  const queryParam = new URLSearchParams({
    page,
    pageSize,
    keyword,
  });
  return await request("GET", `${ARTICLE_URL}?${queryParam}`);
};
export const getArticle = async (articleId) => {
  return await request("GET", `${ARTICLE_URL}/${articleId}`);
};
export const createArticle = async (body) => {
  return await request("POST", `${ARTICLE_URL}`, body);
};

 

더 간단한 wrapper

api를 객체로 만드는 것이 훨씬 더 깔끔하다. 

get / post / patch / delete에 따라서 다른 options를 추가해서

config를 입맛대로 조종할 수 있기 때문이다. 

export const BASE_URL = "https://panda-market-api-crud.vercel.app";
async function request(endpoint, options = {}) {
  try {
    const config = {
      ...options,
      headers: {
        "Content-Type": "application/json",
        ...options.headers,
      },
    };
    const response = await fetch(`${BASE_URL}${endpoint}`, config);

    //응답 상태 코드가 2XX 아닐시 에러 처리하기
    if (!response.ok) {
      throw new Error(data?.message || `Request Failed ${response.status}`);
    }

    return response.json();
  } catch (e) {
    console.error(e);
    throw e;
  }
}
const api = {
  get: (endpoint) => request(endpoint),
  post: (endpoint, data) =>
    request(endpoint, {
      method: "POST",
      body: JSON.stringify(data),
    }),
  patch: (endpoint, data) =>
    request(endpoint, {
      method: "PATCH",
      body: JSON.stringify(data),
    }),
  delete: (endpoint) =>
    request(endpoint, {
      method: "DELETE",
    }),
};
export default api;

https://mnevermore1122.tistory.com/356

 

[JS 기초문법] 리퀘스트 보내기

HTTP란?- OSI 7계층 중 Application 계층은 7계층에서 사용하는 프로토콜 (요청/응답에 대한 정해진 양식)이다.- 우리는 application 개발자가 될 생각이니 가장 외부 계층 프로토콜인 HTTP를 가장 많이 사용

mnevermore1122.tistory.com

그래서 그 방식대로 리팩토링을 진행해보았다. 

https://github.com/quothraven1122/13-sprint-mission-fe/issues/28

 

간단한 interceptor

import axios from "axios";

const api = axios.create({
  baseURL: "https://panda-market-api-crud.vercel.app",
  timeout: 5000,
});
api.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem("accessToken");
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);
api.interceptors.response.use(
  (response) => {
    return response.data; // 🔥 핵심: data만 반환
  },
  (error) => {
    console.error(error);

    // 예: 인증 에러 처리
    if (error.response?.status === 401) {
      console.log("Unauthorized - 로그인 필요");
      // logout or redirect
    }

    return Promise.reject(error); // 🔥 중요
  }
);

이러면 api.get() / api.post()...을 하면 자동으로 intercept해준다.