기존 작업을 하다가 리팩토링을 추가하였다.
기존의 코드는 https://asdf1326.tistory.com/21 전에 글로 올려논 부분이고 이부분을 리팩토링을 진행하였다.
작업 계기는 현 회사에서 불편한 api 호출 방식으로 사용 중인 부분이 있어서 이부분을 개선 작업에 들어갔다.

현회사에서는 src 에 바로 axios 폴더가 들어있었고 그안에 post get put 등등 들어있었다.
현재 가장 많이 사용하는 post get 에대한 부분만 따로 리팩토링을 진행하였다.
기존 코드
import axios from 'axios';
import * as process from 'process';
export const axiosClient = axios.create({
headers: {
'Content-type': 'application/json; charset=UTF-8',
accept: 'application/json,',
},
});
axiosClient.interceptors.request.use(
(config) => ({
...config, withCredentials : true,
}),
(error) => Promise.reject(error)
);
axiosClient.interceptors.response.use(
async (response) => {
return response;
},
(error) => {
const errorMessage = error.response.data;
throw errorMessage;
}
);
export type AxiosMethod = 'get' | 'put' | 'post' | 'delete' | 'patch';
//T: tax-account-console C: company
export type prefixUrl = 'T' | 'C' | 'CT' | 'HOS' | 'U' | 'local' | 'N';
export async function callAxios(
url: string,
method: AxiosMethod,
prefixUrl: prefixUrl,
data?: any,
customContentType?: string
) {
let resData: any;
//url이 있을경우 데이터 요청한다.
if (url !== undefined && url.length > 0) {
//prefix를 붙인다.
let apiUrl = `${process.env.NEXT_PUBLIC_CLIENT_PROXY_URL}`;
switch (prefixUrl) {
case 'T':
apiUrl += process.env.NEXT_PUBLIC_TAX_ACCOUNT_URL + url;
break;
case 'C':
apiUrl += process.env.NEXT_PUBLIC_COMPANY_URL + url;
break;
case 'CT':
apiUrl += process.env.NEXT_PUBLIC_CONTENTS_URL + url;
break;
case 'HOS':
apiUrl += process.env.NEXT_PUBLIC_HOS_URL + url;
break;
case 'U':
apiUrl += process.env.NEXT_PUBLIC_USER_ACCOUNT_URL + url;
break;
case 'N':
apiUrl += process.env.NEXT_PUBLIC_CLIENT_NOTIFICATION + url;
break;
case 'local':
apiUrl += 'http://4954-61-74-228-131.ngrok-free.app/' + url;
break;
}
switch (method) {
case 'get':
resData = await axiosClient.get(apiUrl, {
params: data,
});
break;
case 'post':
resData = await axiosClient.post(apiUrl, data, {
headers: {
'Content-Type': customContentType || 'application/json; charset=UTF-8',
},
});
break;
case 'put':
resData = await axiosClient.put(apiUrl, data);
break;
case 'patch':
resData = await axiosClient.patch(apiUrl, data);
break;
case 'delete':
resData = await axiosClient.delete(apiUrl, {
data,
});
break;
default:
break;
}
}
return resData.data;
}
//header에서 다운로드 파일 이름
const downloadFileName = (res: any) => {
const disposition = res.headers['content-disposition'];
const fileName = decodeURI(
disposition
.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)[1]
.replace(/['"]/g, '')
);
return fileName;
};
export type ExcelParamType = {
url: string;
prefixUrl?: prefixUrl;
data?: any;
};
export interface ExcelParamSetterProps {
setExcelParam: ({ url, data, prefixUrl }: ExcelParamType) => void;
}
//파일 다운로드
export function callFileDownloadAxios(
url: string,
prefixUrl?: prefixUrl,
data?: any
) {
if (url !== undefined && url.length > 0) {
//prefix를 붙인다.
let apiUrl = `${process.env.NEXT_PUBLIC_CLIENT_PROXY_URL}`;
switch (prefixUrl) {
case 'C':
apiUrl += process.env.NEXT_PUBLIC_COMPANY_URL + url;
break;
case 'CT':
apiUrl += process.env.NEXT_PUBLIC_CONTENTS_URL + url;
break;
case 'HOS':
apiUrl += process.env.NEXT_PUBLIC_HOS_URL + url;
break;
case 'U':
apiUrl += process.env.NEXT_PUBLIC_USER_ACCOUNT_URL + url;
break;
}
axiosClient
.get(apiUrl, {
responseType: 'blob',
params: data,
})
.then((res) => {
const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
const link = document.createElement('a');
link.href = downloadUrl;
link.download = downloadFileName(res);
document.body.appendChild(link);
link.click();
link.remove();
});
}
}
//파일 업로드
export async function callFileUploadAxios(url: string, data: any) {
const response = await axiosClient.post(url, data, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
return response.data;
}
기존 코드는 위에같이 적혀있었다. 각 res,req 에대한 타입지정은 없었으며 다른 페이지에서도 지저분하게 적히며 전혀 관리가 안되는 부분들이 많이 차지하였다.

위에 코드처럼 중구 난방으로 관리가 덜된 느낌이 강한 코드들이 퍼져있었다.
처음에 와서 스타트업 특성상 빠른 업무가 우선시 되며 최적화된 코드보다는 기능만 구현하기 위하여작업된 코드와... 신입이 만든.. 구조덕에 난해한 코드가 작성이 되어있었다....정말 고생 많이 했다...
이를 계속 쓰다보면 정리되어있지 않는 상태로 계속 작성이 되면 추후에는 리팩토링이 아니라 리뉴얼 정도의 작업이 되는걸 막기 위하여 타입을 정의 하며 어떻게든 백엔드와 인터페이스 정의를 같이 하여 맞추어나가려고 노력했다....
(같이 일한 백엔드 개발자의 노고가 정말 컷다..ㅠ)

일단 가장 정리하기 쉬운 공지사항 부분먼저 차차 잡아나가려고 해당 구조를 잡았다.
common 에 넣은 이유는 공통적으로 관리에 앞서 구분 하기 위함으로 구조를 만들었다.
api 서버단에서 dto 요청을 미리 클라이언트가 요청할 수 있는 상황을 대비하여 다음과 같이 구조를 짯다.
실제 서비스 엔드포인트에 이름을 따와서 정리를 해주었고 dto 파일을 작성한다.

인터페이스를 지정해주고 응답값을 받을 부분을 적어준다.

인터페이스 구현


함수 생성 (토큰 관련 작업이 추후에 바뀔 가능성이 있다고 하셔서 그부분을 예비로 작성하였다.)
더많은 작업이 필요하지만 대충 리프레쉬 토큰을 가지고 다시 액세스 토큰을 발급 받는 과정을 적을 수있게 미리 공간을 만들어둔다.
useQuery 도 추가적으로 관리 할 수 있도록 추가해준다.

이제 모든 인터페이스 정의는 끝났다 실제로 사용할 수 있게 다른페이지에서 호출 해본다.

notice.ts 는 실제 호출 가능한 함수를 담는 공간으로 작성한다.


이부분은 api 엔드포인트들을 관리하는 공간이다.

위와 같이 만들어준다.

useQuery 를 사용하여 작성한 코드

useQuery 가 필요없을 경우 일반적인 코드 작성 방법이다.
전체 코드는 토이프로젝트로 따로 생성 해두었다.
https://github.com/asdf132645/submoudleReact
GitHub - asdf132645/submoudleReact
Contribute to asdf132645/submoudleReact development by creating an account on GitHub.
github.com
'react' 카테고리의 다른 글
[Redux, Redux-Thunk, Redux-Saga] 주요 개념 정리 (0) | 2023.12.06 |
---|---|
recoil 개념 정리(리액트 리코일: 상태 관리의 새로운 효율성) (0) | 2023.12.06 |
무한 스크롤 페이징 처리 구현 (2) | 2023.12.05 |
useState 비동기 문제 해결 과정 (0) | 2023.12.05 |