はじめに
MSW(Mock Service Worker)は、ネットワークリクエストをブラウザレベルでインターセプト(横取り)する、開発とテストのためのモックAPIライブラリです。
これを使えば、バックエンドが未完成でも、本物のAPIを叩くのと同じコードでフロントエンド開発を進められます。
本記事では、このMSWをReact + Viteプロジェクトで導入する手順を解説します。
導入方法
mswをインストール
npm install msw --save-dev
今回のバージョン
"msw": "^2.11.3"
ワーカー スクリプトを指定されたディレクトリにコピーします。
npx msw init public --save
package.jsonに以下が追加されていることを確認する。
{
"name": "my-app",
"msw": {
"workerDirectory": "public"
}
}
publicディレクトリに以下のスクリプトが追加されていることを確認する。
public/
└── mockServiceWorker.js
リクエストハンドラーを作成
/mocks/handler.tsを作成
以下にはAPIのエンドポイントとレスポンスを記入する。
※異なるポートやホスト名の場合は、完全なURLで指定する必要があります。
import { http, HttpResponse } from 'msw'
export const handlers = [
http.get('/profile', () => {
return HttpResponse.json({
id: 'abc-123',
name: 'Yamada Taro',
email: 'yamada.taro@email.com',
})
}),
]
/mocks/browser.tsを作成
import { setupWorker } from "msw/browser";
import { handlers } from "./handlers";
export const worker = setupWorker(...handlers);
worker.start({
// serviceWorkerオプションを追加
// アプリケーションのベースパスに続けて、サービスワーカーのファイル名を指定
serviceWorker: {
url: "/mockServiceWorker.js",
},
});
main.tsxにmswを追加
本番ビルドでモックが混入しないように環境変数で完全にビルド対象から除外する必要があります。
const setup = async () => {
// 開発環境でのみMSWを有効化
if (import.meta.env.DEV) {
const { worker } = await import("../mocks/browser");
worker.start();
}
};
setup().then(() => {
createRoot(document.getElementById("root")!).render(
<StrictMode>
<RouterProvider router={router} />
</StrictMode>
);
});
mswが動作しているかを確認する
画面を表示し、F12キーで開発者ツールを表示。
Console画面に[MSW] Mocking enabledが表示されていればmswが動作しています。
mockAPIからデータを取得する
コンポーネントからAPIを呼び出しデータを取得する。
以下ではボタン押下時に/profileのデータを取得しているサンプル用のコードです。
import axiosClient from "../../api/axiosClient";
const TopPage = () => {
const fetchUserProfile = async () => {
try {
const response = await axiosClient.get("/profile");
console.log("ユーザー情報:", response.data);
} catch {
// APIエラーを統一的にハンドリングできる
console.error("API呼び出しエラー");
}
};
return (
<>
<div>
<h1>トップページ</h1>
<div onClick={fetchUserProfile}>ボタン</div>
</div>
</>
);
};
export default TopPage;
axiosClientの定義については以下で紹介しています。
Console画面にユーザー情報のデータが出力されていれば完了です。
動的なレスポンスの作成
リクエストのURLやボディの内容に応じて、動的にレスポンスを返すことができます。
import { http, HttpResponse } from 'msw';
const users = [
{ id: '1', name: 'Yamada Taro', email: 'yamada.taro@email.com' },
{ id: '2', name: 'Tanaka Hanako', email: 'tanaka.hanako@email.com' },
{ id: '3', name: 'Suzuki Jiro', email: 'suzuki.jiro@email.com' }
];
export const handlers = [
http.get('/profile/:id', ({ params }) => {
// URLからユーザーIDを取得
const { id } = params;
const user = users.find(u => u.id === id);
if (user) {
return HttpResponse.json(user);
}
// ユーザーが見つからない場合は404エラーを返す
return new HttpResponse(null, { status: 404 });
}),
];
エラーレスポンスの作成
開発中のアプリケーションでは、エラー時のレスポンスも正しく処理できるかどうかを検証する場合があります。
import { http, HttpResponse } from 'msw';
export const handlers = [
http.get('/posts', () => {
// サーバーエラーをシミュレーション
return new HttpResponse('Internal Server Error', { status: 500 });
}),
http.get('/profile/:id', () => {
// データが見つからないエラーをシミュレーション
return new HttpResponse(null, { status: 404 });
}),
];
ディレイ(遅延)をつける方法
実際のAPIは常に即座にレスポンスが返るわけではなく、ネットワークの遅延や処理時間によって数秒かかることもあります。
UI上でローディングアニメーションなどを確認する際に、APIの遅延を加えることができます。
import { http, HttpResponse, delay } from 'msw';
export const handlers = [
http.get('/posts', async () => {
// レスポンスに1秒の遅延を追加
await delay(1000);
return new HttpResponse('Success', { status: 200 });
}),
];
おわりに
MSWは、APIのモック開発をより高度で、実践的なものにするための強力なツールです。
これによりサーバーサイド側のAPI開発を待つことなく、フロントエンド側で効率的な開発を進めることができます。