🤖

Axiosのメリットを説明してみる

に公開1

初めに

前提

私は現在、React + TypeScriptの勉強のため、タスク管理アプリの開発を行っています。開発環境は以下のような構成になっています。

フロントエンド

  • React + TypeScriptで構成
  • ログイン画面やタスク管理画面を実装
  • ローカル環境でコンテナ化

バックエンド

  • PHP(Laravel 12)で構成
  • データベース操作を担当
  • RESTful APIとして機能

フロントエンドとバックエンドは独立したコンテナとして動作し、HTTP APIを通じてデータのやり取りを行っています。

複雑化:初心者の悩み

React初心者の私にとって、フロントエンドからバックエンドAPIへの接続方法は大きな課題でした。JavaScriptの標準的なfetch関数は知っていましたが、実際の開発でどのように使えばよいのか分からず、Claude Codeに実装を相談したところ、AxiosというJavaScriptライブラリを使った実装を提案されました。

問題:なぜAxiosなのか?

そこで疑問が生まれました。

「Axiosを導入することで、具体的にどのようなメリットがあるのか?」

標準のfetch関数でもAPI通信は可能なはずです。なぜわざわざ外部ライブラリを使う必要があるのでしょうか。この記事では、実際の開発経験を通じて感じたAxiosのメリットを詳しく説明していきます。

Axiosの2つの大きなメリット

私はAxiosには大きく分けて2つのメリットがあると感じました。実際に開発を進める中で、特に以下の点で違いを実感しています。

  1. データの扱い方がシンプルで分かりやすい
  2. API管理のしやすさ

それぞれ詳しく見ていきましょう。

メリット1:データの扱い方がシンプルで分かりやすい

Promiseベースの直感的な書き方

AxiosはPromiseベースの設計になっており、async/awaitとの相性が抜群です。

// Axiosを使った場合
const fetchTasks = async () => {
  try {
    const response = await axios.get('/api/tasks');
    setTasks(response.data);
  } catch (error) {
    console.error('タスクの取得に失敗しました:', error);
  }
};

// fetchを使った場合
const fetchTasksWithFetch = async () => {
  try {
    const response = await fetch('/api/tasks');
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const data = await response.json();
    setTasks(data);
  } catch (error) {
    console.error('タスクの取得に失敗しました:', error);
  }
};

Axiosの方が明らかにコードがシンプルで、レスポンスのステータスチェックやJSON変換を意識する必要がありません。

自動JSON処理

AxiosはJSONの変換を自動で行ってくれます。レスポンスデータはresponse.dataでそのまま使用でき、リクエスト時もオブジェクトをそのまま渡すだけでJSON形式に変換されます。

// タスクの作成
const createTask = async (taskData: { title: string; description: string }) => {
  const response = await axios.post('/api/tasks', taskData);
  return response.data;
};

// fetchの場合、手動でJSON変換が必要
const createTaskWithFetch = async (taskData: { title: string; description: string }) => {
  const response = await fetch('/api/tasks', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(taskData), // 手動でJSON変換
  });
  return await response.json(); // 手動でJSON変換
};

リクエスト・レスポンス変換

Axiosでは、リクエストやレスポンスに対して一律の変換処理を設定できます。

// 日付フィールドを自動でDateオブジェクトに変換
axios.defaults.transformResponse = [
  ...axios.defaults.transformResponse,
  (data) => {
    if (data && typeof data === 'object') {
      ['createdAt', 'updatedAt'].forEach(field => {
        if (data[field]) {
          data[field] = new Date(data[field]);
        }
      });
    }
    return data;
  }
];

メリット2:API管理のしやすさ

インターセプター(割り込み処理)

インターセプターは、リクエストやレスポンスを自動的に処理できる強力な機能です。特に認証トークンの管理で威力を発揮します。

// リクエストインターセプター:全てのリクエストに認証トークンを自動追加
axios.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('authToken');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// レスポンスインターセプター:401エラーで自動ログアウト
axios.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) {
      localStorage.removeItem('authToken');
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

この設定により、すべてのAPI呼び出しで認証やエラーハンドリングを意識する必要がなくなります。

統一されたエラーハンドリング

Axiosでは、HTTPステータスコードに基づいた統一的なエラーハンドリングが可能です。

const apiClient = axios.create({
  baseURL: process.env.REACT_APP_API_URL,
  timeout: 10000,
});

// 共通のエラーハンドリング
apiClient.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response) {
      // サーバーエラー
      const { status, data } = error.response;
      switch (status) {
        case 400:
          throw new Error(data.message || 'リクエストが正しくありません');
        case 404:
          throw new Error('リソースが見つかりません');
        case 500:
          throw new Error('サーバーエラーが発生しました');
        default:
          throw new Error('予期しないエラーが発生しました');
      }
    } else if (error.request) {
      // ネットワークエラー
      throw new Error('ネットワークエラーが発生しました');
    }
    return Promise.reject(error);
  }
);

タイムアウト設定とリトライ機能

ネットワークの不安定さに対応するため、タイムアウトやリトライ機能を簡単に設定できます。

const apiClient = axios.create({
  baseURL: process.env.REACT_APP_API_URL,
  timeout: 5000, // 5秒でタイムアウト
});

// リトライ機能の実装例
const retryRequest = async (requestConfig: any, retryCount = 3): Promise<any> => {
  try {
    return await apiClient(requestConfig);
  } catch (error) {
    if (retryCount > 0 && axios.isAxiosError(error) && !error.response) {
      console.log(`リトライします... 残り${retryCount}`);
      await new Promise(resolve => setTimeout(resolve, 1000)); // 1秒待機
      return retryRequest(requestConfig, retryCount - 1);
    }
    throw error;
  }
};

実際の開発での活用例

私のタスク管理アプリでは、以下のようにAxiosを活用しています。

// API設定ファイル(api.ts)
export const apiClient = axios.create({
  baseURL: process.env.REACT_APP_API_URL || 'http://localhost:8000/api',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json',
  },
});

// タスク管理のAPIファイル(taskApi.ts)
import { apiClient } from './api';
export const taskApi = {
  // 全タスク取得
  getAllTasks: () => apiClient.get('/tasks'),
  
  // タスク作成
  createTask: (task: CreateTaskRequest) => 
    apiClient.post('/tasks', task),
  
  // タスク更新
  updateTask: (id: number, task: UpdateTaskRequest) => 
    apiClient.put(`/tasks/${id}`, task),
  
  // タスク削除
  deleteTask: (id: number) => 
    apiClient.delete(`/tasks/${id}`),
};

このように、API呼び出しを関数として整理することで、コンポーネント内のコードがすっきりし、再利用性も向上します。

結論

React + TypeScriptでのタスク管理アプリ開発を通じて、Axiosの導入により以下の効果を実感しました。

開発効率の向上

  • コードの記述量が大幅に削減
  • JSON処理やエラーハンドリングの自動化
  • 認証処理の一元管理

保守性の向上

  • 一貫したAPI通信パターン
  • エラーハンドリングの統一化
  • 設定の集約化

開発者体験の向上

  • 直感的なAPI設計
  • TypeScriptとの良好な相性
  • 豊富なドキュメントとコミュニティサポート

初心者の私でもAxiosを使うことで、認証、タスク管理、プロジェクト管理など、すべての機能で一貫したHTTP通信を実現し、アプリケーション全体の品質向上に大きく貢献しています。

標準のfetch関数も優秀ですが、実際の開発ではAxiosの提供する便利な機能が開発体験を大きく向上させてくれます。React初心者の方には、ぜひAxiosの導入を検討してみることをお勧めします。

Discussion