본문 바로가기
source-code/software

Singleton Pattern을 통한 axios 쿠키 허용

by mattew4483 2023. 8. 20.
728x90
반응형

배경

Cookie를 통해 로그인을 구현하던 와중,
모든 api 요청에 공통된 옵션을 줘야 하는 상황이 생겼다.
 
정확히 말하자면...
axios를 통해 브라우저의 HTTP 요청을 처리하고 있는데, 이때 쿠키를 사용할 경우 withCredentials 옵션을 true로 줘야 한다.
→ 일반적으로 브라우저는 CORS 정책에 따라 다른 도메인으로부터 온 요청에서는 쿠키와 같은 인증 정보를 보낼 수 없다.
(동일 출처 간의 요청에 대해서만 인증 정보를 자동으로 전송)
→ withCredentials 옵션을 통해 브라우저가 해당 도메인 쿠키를 함께 보내도록 허용하는 것!
 
예를 들어 리뷰 생성 시 로그인한 사용자의 쿠키를 함께 보내기 위해서는

import axios, { AxiosResponse } from "axios";

export const createReviewApi = (comment:string)
: Promise<AxiosResponse<{ id: number; review: { id: number } }>> 
=> {
  // 리뷰 생성
  return axios.post(`/review`, {comment}, {
  	withCredentials: true
  });
};

axios에 해당 옵션을 지정해 주면 된다.
 
그런데 문제는...
만약 위와 같은 api가 무척이나 많은 경우라면??

import axios, { AxiosResponse } from "axios";

export const createReviewApi = (comment:string)
: Promise<AxiosResponse<{ id: number; review: { id: number } }>> 
=> {
  return axios.post(`/review`, {comment}, {
  	withCredentials: true // 중복
  });
};

export const createReviewApi = (comment:string)
: Promise<AxiosResponse<{ id: number; review: { id: number } }>> 
=> {
  return axios.post(`/review`, {comment}, {
  	withCredentials: true // 중복
  });
};

export const createReviewApi = (comment:string)
: Promise<AxiosResponse<{ id: number; review: { id: number } }>> 
=> {
  return axios.post(`/review`, {comment}, {
  	withCredentials: true // 중복
  });
};

해당 로직이 계속해서 반복되고 만다!
 

Singleton Pattern

위와 같은 중복을 최소화하기 위해서는 어떻게 해야 할까?
여러 해결책이 있겠지만...
해당 옵션을 지정한 axios 객체를 생성하고, 각 api 요청마다 해당 객체를 재사용하면 되지 않을까?
→ singleton pattern으로 이를 구현할 수 있다!
 

싱글톤 패턴은 소프트웨어 디자인 패턴 중 하나로, 어떤 클래스가 오직 하나의 인스턴스만을 가지도록 보장하는 패턴입니다. 
이렇게 하나의 인스턴스만을 유지하면, 어디서든 그 인스턴스에 접근하여 데이터를 공유하거나 해당 클래스의 기능을 사용할 수 있습니다.
싱글톤 패턴은 주로 리소스를 공유해야 하는 상황에서 사용됩니다. 
예를 들어, 설정 관리, 로깅, 데이터베이스 연결 등에서 인스턴스가 여러 개 생성되는 것을 방지하여 자원을 효율적으로 관리할 수 있습니다

withCredentials 옵션의 axios 인스턴스 역시 서비스 내 여러 개 존재할 필요가 없으므로,
싱글톤 패턴을 통해 해당 인스턴스를 HTTP 요청이 필요한 곳에서 공유해 사용할 수 있겠다.
 
즉 withCredentials 옵션을 통해
브라우저 요청 시 쿠키를 함께 보내는 axios 객체를 생성하고 공유하기 위해서...

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
class AxiosApi {
  private static instance: AxiosApi;
  private axiosInstance: AxiosInstance;

  private constructor() {
    this.axiosInstance = axios.create({
      baseURL: BASE_URL, // 서버 url 환경 변수 
      withCredentials: true, // cookie를 위한 옵션
    });
  }

  // 인스턴스를 반환하는 메서드
  public static getInstance(): AxiosApi {
    if (! AxiosApi.instance) {
      AxiosApi.instance = new AxiosApi();
    }
    return AxiosApi.instance;
  }

  // API 요청 메서드
  get<T = any>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
    return this.axiosInstance.get(url, config);
  }

  post<T = any>(
    url: string,
    data?: any,
    config?: AxiosRequestConfig
  ): Promise<AxiosResponse<T>> {
    return this.axiosInstance.post(url, data, config);
  }

  // 추가적인 HTTP 메서드 추가
}

// 싱글톤 인스턴스 생성
const api = AxiosApi.getInstance();

export default api;

다음과 같이 작성할 수 있겠다!
 

import api from "axiosInstance";

export const createReviewApi = (comment:string)
: Promise<AxiosResponse<{ id: number; review: { id: number } }>> 
=> {
  // 리뷰 생성
  return api.post(`/review`, {comment});
};

export const getReviewApi = (g)
: Promise<AxiosResponse<{ id: number; review: { id: number } }>> 
=> {
  // 리뷰 조회
  return api.get(`/review`);
};

axios를 사용하는 것이 아닌, 생성된 고유한 axios 인스턴스를 사용해 준 모습.
쿠키를 함께 보내야 하는 api 요청 함수들에서 해당 객체를 재사용해줄 수 있을 테다!

728x90
반응형

'source-code > software' 카테고리의 다른 글

[정보처리기사 실기] Database  (0) 2023.09.08
프로그래머의 뇌  (0) 2023.08.30
Template Method pattern  (0) 2023.08.20
Postgresql date_trunc 함수를 통한 날짜별 조회  (0) 2023.08.20
첫 실무 test code 작성 및 고민  (0) 2023.08.20