들어가기 전에..
- 처음 개발 시에는 기본 Axios 코드를 사용하여 일정한 형식없이 데이터를 받아오고, 데이터를 보내는 등 재사용성이 많이 부족했다.
- 또한 많은 파일에서 여기저기 Axios 코드를 사용하여 API 로직이 정리되지 않아, 에러를 고칠때 코드의 가독성이 많이 떨어졌다.
- 팀원분들끼리 Axios instance를 사용하여 API 로직들만 따로 재사용 컴포넌트로 만들기로 결정!!!👩🏻💻
- ...후에.... Axios지옥..시작 😇😱😭
느낀점..
- 우리 팀은 Axios instance를 만든 이유가 사실 코드를 재사용하기 위해서였다.. 하지만 구현 코드를 보면 알수 있듯이..정말 재사용성은...거의 없다..😭😇
단, API 로직를 따로 구분해 코드의 가독성을 높였다는 것에 의의를 두기로 했다..
- 사실 Axios instance를 만들면서 정말 많이 힘들고, 후회했던 것이..데이터 로직을 쓸때 안에 로직으로 받는 인자들에 state값들이 들어가면서 이러저리 꼬였기 때문이다.
이 꼬인것들을 해결하면서 사실 타입들이 꼬여서 Axios의 재사용성이 떨어졌다..
또한 단순히 필요한 곳에 Axios를 썼을때 잘 되었던 백엔드와의 통신이 Axios instance을 쓰면서..여기저기 에러가 나면서..해결하기 위해 2일정도.. 함께한 팀원과 밤을 샜다..
Axios instance만들기
axios.create([config])
- 사용자 지정 config로 새로운 Axios instance를 만들수 있다.
구현 코드
import { APIS } from "./APIs";
import axios from "axios";
import { getLocalStorage } from "../Api/localStorage";
import { toast } from "react-toastify";
let token = getLocalStorage("access_token");
export const BaseInstance = axios.create({
baseURL: import.meta.env.VITE_APP_API_URL,
headers: {
Authorization: token,
},
});
export const getDetailsAndReviews = (stateD: React.Dispatch<any>, stateR: React.Dispatch<any>, storeIdx: number) => {
const getPharmDetail = async () => {
return BaseInstance.get(`${APIS.GET_PHARMDETAILS}/${storeIdx}`)
.then((response) => stateD(response.data.response))
.catch((error) => {
console.log(error);
});
};
const getReviewList = async () => {
return BaseInstance.get(`${APIS.GET_REVIEWS}/${storeIdx}/review`)
.then((response) => stateR(response.data.response.storeReviews))
.catch((error) => {
console.log(error);
});
};
axios.all([getPharmDetail(), getReviewList()]);
};
export const likePharmacy = async (storeidx: number | undefined, value: TYPE_boolean, state: TYPE_setLike) => {
return BaseInstance.post(`${APIS.POST_LIKE}/${storeidx}/pick`)
.then(() => state(!value))
.catch((error) => {
console.log(error);
});
};
export const getUser = async (
userIdx: number,
state: React.Dispatch<React.SetStateAction<TYPE_UserInfo | undefined>>,
) => {
return BaseInstance.get(`${APIS.GET_USER_INFO}/${userIdx}`)
.then((response) => state(response.data.response))
.catch((error) => {
console.log(error);
});
};
export const postUserImg = async (data: object) => {
return BaseInstance.post(APIS.POST_USER_IMG, data)
.then(() => location.reload())
.catch((error) => {
console.log(error);
});
};
export const findPW = async (findPassword: string) => {
return BaseInstance.patch(APIS.PATCH_FINDPW, { email: findPassword }).catch((error) => {
console.log(error);
});
};
export const getReview = async (
storeIdx: number | undefined,
state: React.SetStateAction<React.SetStateAction<any>>,
) => {
return BaseInstance.get(`${APIS.GET_REVIEWS}/${storeIdx}/review`)
.then((response) => {
state(response.data.response.storeReviews);
})
.catch((error) => {
console.log("리뷰 불러오던 중 중 에러 발생");
console.log(error);
});
};
export const postReview = async (
storeIdx: number | undefined,
data: any,
state: React.SetStateAction<React.SetStateAction<any>>,
) => {
return BaseInstance.post(`${APIS.POST_REVIEWS}/${storeIdx}/review`, data)
.then(() => state(false))
.catch((error) => {
console.log(error);
});
};
export const patchReview = async (
storeIdx: number | undefined,
reviewIdx: number | undefined,
data: any,
state: any,
) => {
return BaseInstance.patch(`${APIS.POST_REVIEWS}/${storeIdx}/review/${reviewIdx}`, data)
.then(() => state(false))
.catch((error) => {
console.log(error);
});
};
export const deleteReview = async (storeIdx: number | undefined, reviewIdx: number) => {
return BaseInstance.delete(`${APIS.DELETE_REVIEWS}/${storeIdx}/review/${reviewIdx}`).catch((error) => {
console.log(error);
});
};
export const reportReview = async (storeIdx: number | undefined, reviewIdx: number, data: object) => {
return BaseInstance.post(`${APIS.POST_REPORT_REVIEW}/${storeIdx}/review/${reviewIdx}/report`, data)
.then(() =>
toast.success("리뷰를 신고했습니다.", {
position: "top-center",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
}),
)
.catch((error) => {
console.log(error);
});
};
export const postReply = async (reviewIdx: number, data: object, stateC: any, stateF: any) => {
return BaseInstance.post(`${APIS.POST_REPLY}/${reviewIdx}/reply`, data)
.then(() => stateC(""))
.then(() => stateF(false))
.catch((error) => {
console.log(error);
});
};
export const patchReply = async (reviewIdx: number, replyIdx: number, data: any, stateF: any) => {
return BaseInstance.patch(`${APIS.PATCH_REPLY}/${reviewIdx}/reply/${replyIdx}`, data)
.then(() => stateF(false))
.catch((error) => {
console.log(error);
});
};
export const deleteReply = async (reviewIdx: number, replyIdx: number) => {
return BaseInstance.delete(`${APIS.DELETE_REPLY}/${reviewIdx}/reply/${replyIdx}`).catch((error) => {
console.log(error);
});
};
const getUserInfo = async (
userIdx: number,
stateI: any,
stateN: React.Dispatch<React.SetStateAction<string>>,
stateA: React.Dispatch<React.SetStateAction<string>>,
) => {
return BaseInstance.get(`${APIS.GET_USER_INFO}/${userIdx}`)
.then((response) => {
stateI(response.data.response);
stateN(response.data.response.name);
stateA(response.data.response.address);
})
.catch((error) => {
console.log(error);
});
};
const patchUserInfo = async (userIdx: number, data: object, state: React.Dispatch<React.SetStateAction<boolean>>) => {
return BaseInstance.patch(`${APIS.PATCH_USER_INFO}/${userIdx}`, data)
.then(() => state(false))
.then(() => location.reload())
.catch((error) => {
console.log(error);
});
};
const getLikedPharmList = async (userIdx: number, state: React.Dispatch<React.SetStateAction<never[]>>) => {
return BaseInstance.get(`${APIS.GET_MY_LIKES}/${userIdx}/pick`)
.then((response) => state(response.data.response))
.catch((error) => {
console.log(error);
});
};
const getMyReviews = async (userIdx: number, state: React.Dispatch<React.SetStateAction<never[]>>) => {
return BaseInstance.get(`${APIS.GET_MYREVIEWS}/${userIdx}`)
.then((response) => state(response.data.response.reviews))
.catch((error) => {
console.log(error);
});
};
export const UserInstance = {
getUserInfo,
patchUserInfo,
getLikedPharmList,
getMyReviews,
};
const getPharmInfo = async (storeIdx: number, state: React.Dispatch<any>) => {
return BaseInstance.get(`${APIS.GET_PHARMDETAILS}/${storeIdx}`)
.then((response) => state(response.data.response))
.catch((error) => {
console.log(error);
});
};
const getPharmacistInfo = async (userIdx: number, state: any) => {
return BaseInstance.get(`${APIS.GET_USER_INFO}/${userIdx}`)
.then((response) => state(response.data.response))
.catch((error) => {
console.log(error);
});
};
const postPharmImg = async (data: object) => {
return BaseInstance.post(APIS.POST_PHARM_IMG, data)
.then(() => location.reload())
.catch((error) => {
console.log(error);
});
};
export const PharmInstance = {
getPharmInfo,
getPharmacistInfo,
postPharmImg,
};
const getReports = async (stateList: any, page: number, stateLast: any, preventRef: any) => {
return BaseInstance.get(APIS.GET_ADMIN_REPORTED, { params: { page, size: 20 } })
.then((response) => {
stateList((prev: any) => [...prev, ...response.data.response.reportedReviews]);
preventRef = true;
if (!response.data.pageInfo.isFinish || response.data.pageInfo.totalPage === response.data.pageInfo.page + 1)
stateLast(true);
})
.catch((error) => {
console.log(error);
});
};
const deleteReportedReview = async (data: object) => {
return BaseInstance.delete(APIS.DELETE_ADMIN_REVIEW_DELETE, { data })
.then(() =>
toast.warning("선택한 리뷰들을 삭제합니다.", {
position: "top-center",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
}),
)
.then(() => setTimeout(() => location.reload(), 2000))
.catch((error) => {
console.log(error);
});
};
const restoreReview = async (data: object) => {
return BaseInstance.post(APIS.POST_ADMIN_REVIEW_RESTORE, data)
.then(() =>
toast.warning("선택한 리뷰들을 복구합니다.", {
position: "top-center",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
}),
)
.then(() => setTimeout(() => location.reload(), 2000))
.catch((error) => {
console.log(error);
});
};
const getUsers = async (stateList: any, page: number, stateLast: any, preventRef: any) => {
return BaseInstance.get(APIS.GET_ADMIN_USERS, { params: { page, size: 20 } })
.then((response) => {
stateList((prev: any) => [...prev, ...response.data.response]);
preventRef = true;
if (!response.data.pageInfo.totalPage || response.data.pageInfo.totalPage === response.data.pageInfo.page + 1)
stateLast(true);
})
.catch((error) => {
console.log(error);
});
};
const blockUsers = async (time: number, data: object) => {
if (time === 0) alert("정지옵션을 선택해주세요");
return BaseInstance.post(APIS.POST_ADMIN_BLOCK, data, { params: { period: time } })
.then(() =>
toast.warning("선택한 계정들을 정지합니다.", {
position: "top-center",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
}),
)
.then(() => setTimeout(() => location.reload(), 2000))
.catch((error) => {
console.log(error);
});
};
const fireUsers = async (data: object) => {
return BaseInstance.post(APIS.POST_ADMIN_FIRE, data)
.then(() =>
toast.warning("선택한 계정들을 강퇴합니다.", {
position: "top-center",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
}),
)
.then(() => setTimeout(() => location.reload(), 2000))
.catch((error) => {
console.log(error);
});
};
const restoreUsers = async (data: object) => {
return BaseInstance.post(APIS.POST_ADMIN_RESTORE, data)
.then(() =>
toast.warning("선택한 계정들을 복구합니다.", {
position: "top-center",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
}),
)
.then(() => setTimeout(() => location.reload(), 2000))
.catch((error) => {
console.log(error);
});
};
const getCertificates = async (stateList: any, page: number, stateLast: any, preventRef: any) => {
return BaseInstance.get(APIS.GET_ADMIN_CERTS, { params: { page, size: 20 } })
.then((response) => {
stateList((prev: any) => [...prev, ...response.data.response]);
preventRef = true;
if (!response.data.pageInfo.totalPage || response.data.pageInfo.totalPage === response.data.pageInfo.page + 1)
stateLast(true);
})
.catch((error) => {
console.log(error);
});
};
const successCertify = async (data: object) => {
return BaseInstance.post(APIS.POST_ADMIN_CERTIFY, data)
.then(() =>
toast.success("선택한 약사인증신청을 승인합니다.", {
position: "top-center",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
}),
)
.then(() => setTimeout(() => location.reload(), 2000))
.catch((error) => {
console.log(error);
});
};
const deniedCertify = async (data: object) => {
return BaseInstance.post(APIS.POST_ADMIN_DENY, data)
.then(() =>
toast.error("선택한 약사인증신청을 반려합니다.", {
position: "top-center",
autoClose: 2000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
}),
)
.then(() => setTimeout(() => location.reload(), 2000))
.catch((error) => {
console.log(error);
});
};
export const AdminInstance = {
getReports,
deleteReportedReview,
restoreReview,
getUsers,
blockUsers,
fireUsers,
restoreUsers,
getCertificates,
successCertify,
deniedCertify,
};