Refactor: React API 계층 분리 (1)

Singsoong·2023년 7월 6일
0

react

목록 보기
3/7
post-thumbnail

📌 API 레이어를 분리해야 하는 이유

  • UI 코드와 데이터 레이어 코드의 결합도가 높아진다.
  • 같은 데이터를 가져오는 코드가 중복되어 분산 존재하게 된다.
  • 컴포넌트와 API 레이어 관심사 혼재는 코드 읽기를 어렵하게 한다.

📌 분리하기에 앞서서

  • 현재 컴포넌트 내에 API를 호출하는 함수가 있다.
  • 한번에 리팩토링을 진행하기엔 디버깅이 힘든 과정이 있어서 단계별로 차근차근히 진행하려 함
  • 서버 데이터 fetching 및 caching 라이브러리로 tanstack query를 사용하였음

📌 폴더 구조

└─ src
   ├─ apis
   │  ├─ api
   │  │  ├─ Auth
   │  │  │  ├─ login.js
   │  │  │  └─ useLogin.js
   │  │  ├─ Category
   │  │  │  └─ getCategory.js
   │  │  ├─ Device
   │  │  │  └─ getDevices.js
   │  │  └─ User
   │  │     ├─ getUser.js
   │  │     └─ patchUser.js
   │  ├─ services
   │  │  └─ silentRefresh.js
   │  └─ utils
   │     ├─ axios.js
   │     ├─ index.js
   │     └─ queryClient.js
  • api : api를 요청하고 응답 받는 API 함수
  • services : response 데이터를 정제 하는 함수
  • utils : 공통 함수

📌 Refactoring

📄 1. axios 모듈화

  • 적용 전
async function getDevices(accessToken) {
  const response = await axios.get(`${BASE_URL}/api/devices`, {
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  });
  return response.data;
}

async function getCategory(accessToken) {
  const response = await axios.get(`${BASE_URL}/api/category`, {
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  });
  return response.data;
}
  • axios로 서버와 통신하는 기존 코드에서 매번 BASE_URL 을 import 하여 호출해야함
  • 또한 header에 인증 부분이 중복됨
// utils\axios.js
import Axios from "axios";
import { BASE_URL } from "../../constants";

export const axios = Axios.create({
  baseURL: BASE_URL,
});

axios.interceptors.request.use(
  (config) => {
    const accessToken = getToken();

    config.headers["Authorization"] = `Bearer ${accessToken}`
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
)
  • 공통적으로 사용할 axios 인스턴스를 생성함

  • 요청이 전달되기 전에 작업을 수행할 수 있는 interceptors를 사용하여 header의 Authorization 필드에 accesstoken을 넣음

  • 적용 후

import { axios } from "../../utils";

export async function getCategory(accessToken) {
  const response = await axios.get("/category");
  return response.data;
}
  • 직전에 생성한 공통으로 사용할 axios 인스턴스를 import하여 사용
  • endpoint만 명시하여 사용하면 됨

📖 참고 : BASE_URL

  • BASE_URL 은 환경변수로 관리하여 개발 환경과 배포 환경에서의 주소 변경을 수월하게 함
  • build 시에 env.production이 적용
// env.development
REACT_APP_HOME_URL=//222.222.222.222:22222/api
// env.production
REACT_APP_HOME_URL=//xxx.com/api
  • 프로젝트 내 constants 폴더를 만들어 환경변수 및 상수들을 관리
// constants\index.js
export * from "./api";
export * from "./token";
// constants\api.js
export const BASE_URL = process.env.REACT_APP_HOME_URL

📄 2. Query Client 모듈화

  • 기존에는 모든 query 훅에서 기본 설정 관련 정보를 넣어줬음
  • 모든 쿼리에서 사용하는 중복 설정 정보를 중앙 집중식으로 관리하려함
// utils\queryClient.js
import { QueryClient } from "@tanstack/react-query";

export const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      cacheTime: 600000, // (예시)
    },
    // ... 추가적으로 설정할 옵션들
  },
});
  • 모듈화한 queryClient를 컴포넌트 최상위에 위치한 QueryClientProvider에 인자로 주면 됨
import { queryClient } from "./apis/utils";

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      // ...
      <Router />
    </QueryClientProvider>
  );
}

참고 :
https://ghost4551.tistory.com/163 (리팩토링_API 모듈 분리)
https://itchallenger.tistory.com/903 (Refactoring React: Separate API Layer)

profile
Frontend Developer

0개의 댓글