Axiosのメリットを説明してみる
初めに
前提
私は現在、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つのメリットがあると感じました。実際に開発を進める中で、特に以下の点で違いを実感しています。
- データの扱い方がシンプルで分かりやすい
- 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
つ ky