따꿍의 프로젝트
[Sprint 3] API 호출 공통 래퍼 (Axios의 interceptor / Fetch Wrapper) 본문
발단
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해준다.
'웹프로젝트 > 코드잇' 카테고리의 다른 글
| MongoDB 연결 중 ECONNREFUSED 에러 (0) | 2026.04.30 |
|---|---|
| [Sprint 5] React 적용 (path alias 설정, layout 설정, element 사이사이에만 라인 설정하기, 반응형 디자인, useMediaQuery) (0) | 2026.04.24 |
| [Sprint 3] npm script로 html 열기 (0) | 2026.04.15 |
| [코드리뷰] 불필요한 태그 정리 / 코드 분리 / 시멘틱 태그 / 반응형 구현 (0) | 2026.04.10 |
| [Git] 되돌리고 싶을때 사용하는 git 명령어에 대한 개인적인 git 실험 (0) | 2026.04.02 |
