Axiosを活用したフロントエンドWeb開発のポイント

AxiosはブラウザでもNode.jsでも動作するHTTPクライアントです。
私のユースケースではサーバサイドのアプリケーションをNode.jsで作ることがあまりないので、フロントエンドでのAxiosの使い方のメモです。
ちなみにAxiosはドキュメント含めて放置されているPRが溜まっているので、何度かPRを出そうと思って断念してますw

HTML上でちょっとリクエストを送信したいみたいなケースは以下のようなコードになります。
fetchでも良いのですが、レスポンスやエラーが扱いやすいので基本的にaxiosを利用しています。

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
  axios.defaults.baseURL = "https://api.example.com";
  axios.get("/path/to/api")
    .then(res => console.log(res.data))
    .catch(e => console.error(e));

  const params = { key: "value" };
  axios.post("/path/to/api", params)
    .then(res => console.log(res.data))
    .catch(e => console.error(e));
</script>

APIクライアントを定義する(TypeScript)

APIクライアントをモジュールとして定義して、必要な場所でAPIを実行する関数をimportして利用します。
認証の有無やAPIのエンドポイント毎などで複数定義する想定ですが、1つしか定義しない場合などはaxios.defaultsに設定してaxios.getのように利用する事も可能です。

import axios from "axios";

// Authorizationヘッダに設定するトークンを取得する関数(cookieに保存されているトークンを取得するなど)
import { getToken } from "./token";

// API Clientのオプション
const apiOptions = {
  baseURL: import.meta.env.VITE_API_URL, // viteを利用している場合
  timeout: 60000, // 60秒
  headers: {
    "Content-Type": "application/json"
  }
}

// API Clientのインスタンスを生成
const api = axios.create(apiOptions);

// リクエスト送信の前処理
const authRequestInterceptor = (config: InternalAxiosRequestConfig) => {
  const token = getToken();
  if (token) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config;
}
api.interceptors.request.use(authRequestInterceptor)

// レスポンスのステータスコードが2XXの時の処理
const responseSuccessInterceptor = (response): Promise<any> => {
  return response;
}

// レスポンスのステータスコードが2XX以外の時の処理
const responseErrorInterceptor = (response): Promise<any> => {
  switch (error.response?.status) {
    case 401:
      // 認証に失敗した時の処理など
      window.location.href = "/path/to/login";
    default:
      console.error(error.response);
  }
  return Promise.reject(error);
}
api.interceptors.response.use(responseSuccessInterceptor, responseErrorInterceptor);


export interface Product {
  id: number;
  name: string;
  price: number;
}

export const getProduct = (id: number): AxiosPromise<Product> => {
  return client.get(`/products/${id}`);
}

export const getProducts = (): AxiosPromise<Product[]> => {
  return client.get("/products");
}

APIの使用例

reactコンポーネントでの使用例。

import React, { useEffect, useState } from "react";

import { getProducts, Product } from "./apiClient";

export const SomeComponent: React.FC = () => {
  const [products, setProducts] = useState<Product[]>([]);

  useEffect(() => {
    (async () => {
      try {
        const { data } = await getProducts();
        setProducts(data);
      } catch (err) {
        console.error(err);
      }
    })();
  }, []);

  return (
    <>
      {products && products.map((product) => {
        <div key={product.id}>
          <p>{product.name}: {product.price}</p>
        </div>
      })}
    </>
  )
}