🙆‍♀️

Axios をもっと使いやすくする設定

2022/10/14に公開

API とのデータ通信で Axios をよく使っています。少し前までは、以下のように Axios をインスタンス化した際に「共通と思われる」振る舞いを定義して利用していました。

参照: bulletproof-react/axios.ts at master · alan2207/bulletproof-react

import Axios, { AxiosRequestConfig } from 'axios';

import { API_URL } from '@/config';
import { useNotificationStore } from '@/stores/notifications';
import storage from '@/utils/storage';

function authRequestInterceptor(config: AxiosRequestConfig) {
  const token = storage.getToken();
  if (token) {
    config.headers.authorization = `${token}`;
  }
  config.headers.Accept = 'application/json';
  return config;
}

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

axios.interceptors.request.use(authRequestInterceptor);
axios.interceptors.response.use(
  (response) => {
    return response.data;
  },
  (error) => {
    const message = error.response?.data?.message || error.message;
    useNotificationStore.getState().addNotification({
      type: 'error',
      title: 'Error',
      message,
    });

    return Promise.reject(error);
  }
);

しかし以下のようなケースもアプリケーション開発中に往々にして存在します。

  • Axios インスタンスに設定した baseURL とは別のドメインの API へのアクセス
  • アクセストークンが不要な API へのアクセス
  • Auth0 を使うので、アクセストークンは React Hooks から取得したい

等々。こういった場合に先程の共通化した Axios インスタンスは利用できません。デフォルトの振る舞いを予め定義しておいて、Axios を利用する際に設定する方法のほうが使い勝手が良い気がします。

import Axios, { CreateAxiosDefaults } from "axios";
import camelcaseKeys from "camelcase-keys";
import snakecaseKeys from "snakecase-keys";

import { API_URL } from "@/config";

type HttpProps = {
  isConvertKeys?: boolean;
  accept?: string;
  token?: string;
  axiosDefaults?: CreateAxiosDefaults;
};

const defaultHttpProps: HttpProps = {
  isConvertKeys: true,
  accept: "application/json",
  axiosDefaults: {
    baseURL: API_URL,
  },
};

export class Http {
  public static axios(props?: HttpProps) {
    const { axiosDefaults, isConvertKeys, accept, token } = {
      ...defaultHttpProps,
      ...props,
    };

    const axios = Axios.create({ ...axiosDefaults });

    axios.interceptors.request.use((config) => {
      if (config.headers && accept) {
        config.headers.Accept = accept;
      }

      if (config.headers && token) {
        config.headers.authorization = `bearer ${token}`;
      }

      if (isConvertKeys) {
        config = snakecaseKeys(config);
      }

      return config;
    });

    axios.interceptors.response.use(
      (response) => {
        if (isConvertKeys) {
          camelcaseKeys(response.data, { deep: true });
        }
        return response;
      },
      (error) => {
        return Promise.reject(error);
      }
    );

    return axios;
  }
}

利用する際はこうします。

Http.axios({ token: 'xxxxx' }).get(....)

別の baseURL の API にアクセスしたい場合はこうします。

Http.axios({
  axiosDefaults: {
    baseURL: 'https://hogehoge.com',
  }
}).get(...)

これでかなり使い勝手のよい Axios のラッパーになったかと思います。

Discussion