React 기술면접 3-5. axios, instance, interceptor

강연주·2025년 1월 6일

🙋‍♀️ 기술면접

목록 보기
101/112

axios의 instance, interceptor

  1. axios의 instance와 interceptor를 이해하고 활용하여 좀 더 깊은 수준의 API call을 할 수 있습니다.
    • 답변)
      • 의도:
        • axios의 instance와 interceptor에 대한 이해, 활용 과 API 호출을 효과적으로 관리하는 능력 평가.
      • 팁:
        • axios instance와 interceptor의 개념 설명.
        • instance와 interceptor 사용 이유 설명.
        • instance와 interceptor 활용 예제 떠올리기.
      • 모범답안:
        • axios instance는 기본 설정을 가진 axios 인스턴스를 생성하여, 여러 요청에서 재사용할 수 있게 해준다.
        • interceptor는 요청 또는 응답을 가로채어, 추가적인 처리를 할 수 있게 해준다.
        • instance와 interceptor를 사용하면 인증 토큰 설정, 오류 처리 등을 중앙에서 관리할 수 있다.

Instance

기본 설정이 적용된 axios의 '복사본'을 만드는 개념이다.
서로 다른 baseURL이나 설정이 필요한 경우 유용하다.

🖥️ javascript

// 실제로 생성된 axios 인스턴스 (개별 객체) 예시
const authApi = axios.create({
  baseURL: 'https://auth.example.com',
  timeout: 5000,
  headers: {
    'Content-Type': 'application/json'
  }
});

const productApi = axios.create({
  baseURL: 'https://product.example.com',
  timeout: 3000,
  headers: {
    'Content-Type': 'application/json'
  }
});

// 사용 예시
authApi.post('/login', { username, password });
productApi.get('/products');
  • 인스턴스 생성 팩토리 함수
    동일한 설정 패턴을 가진 여러 axios 인스턴스를 생성하는 데 사용되는 템플릿 역할을 한다.
🖥️ javascript

// 이것들이 각각 axios 인스턴스
const authApi = axios.create({...});
const productApi = axios.create({...});
const userApi = axios.create({...});

// createAxiosInstance는 위와 같은 인스턴스들을 생성하는 팩토리 함수
const authApi = createAxiosInstance('https://auth.example.com');
const productApi = createAxiosInstance('https://product.example.com');
const userApi = createAxiosInstance('https://user.example.com');

➡️ 각 인스턴스는 자신만의 고유한 설정(baseURL, timeout, headers 등)을 가진 독립적인 axios 객체다. 이렇게 생성된 인스턴스들은 서로 다른 API 엔드포인트나 설정을 가질 수 있으면서도, 인터셉터나 기본 설정 같은 공통 기능을 공유할 수 있다.


Interceptor

요청이나 응답을 보내기 전 또는 후에 가로채서 처리할 수 있는 기능이다.
공통적으로 처리해야 하는 로직을 중앙에서 관리할 수 있다.

🖥️ javascript

// 요청 인터셉터 예시
api.interceptors.request.use(
  config => {
    // 요청 보내기 전 공통으로 처리할 작업
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    // 로딩 상태 시작
    store.dispatch(setLoading(true));
    return config;
  },
  error => {
    store.dispatch(setLoading(false));
    return Promise.reject(error);
  }
);

// 응답 인터셉터 예시
api.interceptors.response.use(
  response => {
    // 응답 데이터 처리
    store.dispatch(setLoading(false));
    return response;
  },
  error => {
    store.dispatch(setLoading(false));
    
    // 에러 공통 처리
    if (error.response.status === 401) {
      store.dispatch(logout());
      router.push('/login');
    }
    
    if (error.response.status === 403) {
      alert('권한이 없습니다');
    }
    
    return Promise.reject(error);
  }
);

인터셉터 유무의 차이점

1. 인터셉터 없이 구현

🖥️ javascript

// API 호출마다 토큰 처리, 에러 처리 등을 반복해서 작성해야 합니다
const getUsers = async () => {
  const token = localStorage.getItem('token');
  try {
    const response = await axios.get('/users', {
      headers: { Authorization: `Bearer ${token}` }
    });
    return response.data;
  } catch (error) {
    if (error.response.status === 401) {
      logout();
      router.push('/login');
    }
    throw error;
  }
};

const createUser = async (userData) => {
  const token = localStorage.getItem('token');
  try {
    const response = await axios.post('/users', userData, {
      headers: { Authorization: `Bearer ${token}` }
    });
    return response.data;
  } catch (error) {
    if (error.response.status === 401) {
      logout();
      router.push('/login');
    }
    throw error;
  }
};

2. 인터셉터 사용

🖥️ javascript

// 인터셉터 설정 (한 번만 설정)
const api = axios.create({ baseURL: '/api' });

api.interceptors.request.use(config => {
  const token = localStorage.getItem('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

api.interceptors.response.use(
  response => response.data,
  error => {
    if (error.response.status === 401) {
      logout();
      router.push('/login');
    }
    return Promise.reject(error);
  }
);

// API 호출 코드가 매우 간단해진다.
const getUsers = () => api.get('/users');
const createUser = (userData) => api.post('/users', userData);

인터셉터 장점

  • 코드 중복 제거
    • 토큰 추가, 에러 처리 등의 공통 로직을 한 곳에서 관리
    • 변경 사항이 있을 때 한 곳만 수정하면 됨
  • 관심사 분리
🖥️ javascript

// API 로직에만 집중할 수 있음
const UserAPI = {
  getUser: (id) => api.get(`/users/${id}`),
  updateUser: (id, data) => api.put(`/users/${id}`, data),
  deleteUser: (id) => api.delete(`/users/${id}`)
};
  • 일관성 유지
🖥️ javascript

// 모든 API 호출이 동일한 방식으로 처리됨
api.interceptors.response.use(
  response => {
    // 모든 응답에 대해 동일한 데이터 처리
    logApiCall(response);  // 로깅
    setLoadingState(false);  // 로딩 상태 관리
    return response.data;
  },
  error => {
    // 모든 에러에 대해 동일한 처리
    handleApiError(error);  // 에러 처리
    setLoadingState(false);  // 로딩 상태 관리
    return Promise.reject(error);
  }
);
  • 유지보수 용이성
🖥️ javascript

  // 새로운 요구사항 추가가 쉬움
 api.interceptors.request.use(config => {
  
  // 새로운 요구사항: API 버전 헤더 추가
  config.headers['API-Version'] = 'v2';
  
  // 새로운 요구사항: 디바이스 정보 추가
  config.headers['Device-Info'] = getDeviceInfo();
  
  return config;
});
  • 비즈니스 로직에 집중 가능, 코드 가독성 향상, 유지보수가 용이, 잠재적 실수 감소
    특히 대규모 프로젝트에서 API 호출이 많을 때 인터셉터의 장점이 더욱 돋보인다.

실제 사용 예시

🖥️ javascript

// api/index.js
// 인스턴스 생성 팩토리 함수
const createAxiosInstance = (baseURL) => {
  const instance = axios.create({
    baseURL,
    timeout: 5000,
    headers: {
      'Content-Type': 'application/json'
    }
  });

  // 요청 인터셉터
  instance.interceptors.request.use(
    config => {
      const token = localStorage.getItem('token');
      if (token) {
        config.headers.Authorization = `Bearer ${token}`;
      }
      return config;
    },
    error => Promise.reject(error)
  );

  // 응답 인터셉터
  instance.interceptors.response.use(
    response => response.data,
    error => {
      switch (error.response.status) {
        case 401:
          handleUnauthorized();
          break;
        case 403:
          handleForbidden();
          break;
        case 500:
          handleServerError();
          break;
      }
      return Promise.reject(error);
    }
  );

  return instance;
};

// 여러 개의 API 인스턴스 생성
export const authApi = createAxiosInstance('https://auth.example.com');
export const productApi = createAxiosInstance('https://product.example.com');

이렇게 Instance와 Interceptor를 활용하면

  • 코드 중복을 줄일 수 있다.
  • API 호출 관련 로직을 중앙에서 관리 가능.
  • 에러 처리를 일관되게 수행.
  • 토큰 관리나 로딩 상태 등 공통 기능을 쉽게 구현할 수 있다.

profile
아무튼, 개발자

0개의 댓글