MSWとは何か
MSW(Mock Service Worker)は、ブラウザとNode.js環境でAPIリクエストをインターセプト(横取り)し、モックレスポンスを返すことができるライブラリです。Service Worker APIを活用してネットワークレベルでリクエストを捕捉するため、アプリケーションコードを変更することなくAPIのモッキングが可能です。
なぜMSWが必要なのか
フロントエンド開発では、バックエンドAPIが未完成の状態で開発を進めたり、テスト環境で安定したレスポンスが必要になる場面があります。従来のモック手法では、fetchやaxiosなどのHTTPクライアントを直接モックする必要がありましたが、MSWを使用することで以下のメリットが得られます。
- 実装に依存しない: HTTPクライアントの種類(fetch、axios、XMLHttpRequest)に関わらず動作
- 本番環境に近い: 実際のネットワークリクエストと同じ挙動を再現
- 開発体験の向上: ブラウザの開発者ツールでリクエスト/レスポンスを確認可能
MSWの動作原理
ブラウザ環境での動作
ブラウザでは、Service Workerを登録してネットワークリクエストをインターセプトします。アプリケーションが発行したリクエストは、まずService Workerに到達し、定義されたハンドラーと照合されます。マッチするハンドラーがあればモックレスポンスを返し、なければ実際のネットワークリクエストとして処理されます。
Node.js環境での動作
Node.js環境(Vitestなどのテスト実行時)では、node-request-interceptor
ライブラリを使用してHTTPモジュールのリクエストをインターセプトします。これにより、テスト環境でも同じハンドラー定義を使用してAPIをモックできます。
基本的なセットアップ
MSWのセットアップは、以下の手順で行います。
1. インストール
npm install msw@2.7.3 --save-dev
2. Service Workerファイルの生成
npx msw init public/ --save
このコマンドでpublic/mockServiceWorker.js
が生成されます。
3. ハンドラーの定義
src/mocks/handlers.ts
を作成:
import { http, HttpResponse } from 'msw'
export const handlers = [
// GETリクエストのモック
http.get('/api/users', () => {
return HttpResponse.json([
{ id: 1, name: '田中太郎', email: 'tanaka@example.com' },
{ id: 2, name: '佐藤花子', email: 'sato@example.com' }
])
}),
// POSTリクエストのモック
http.post('/api/users', async ({ request }) => {
const body = await request.json() as { name: string; email: string }
return HttpResponse.json({
id: 3,
name: body.name,
email: body.email
}, { status: 201 })
})
]
4. ワーカーの設定
src/mocks/browser.ts
を作成:
import { setupWorker } from 'msw/browser'
import { handlers } from './handlers'
export const worker = setupWorker(...handlers)
5. アプリケーションでの初期化
src/main.ts
で開発環境時のみMSWを起動:
import { createApp } from 'vue'
import App from './App.vue'
async function enableMocking() {
if (import.meta.env.MODE !== 'development') {
return
}
const { worker } = await import('./mocks/browser')
return worker.start({
onUnhandledRequest: 'bypass' // ハンドラーがないリクエストは通常通り処理
})
}
enableMocking().then(() => {
createApp(App).mount('#app')
})
より実践的な使い方
動的なレスポンス
パスパラメータやクエリパラメータに基づいて動的なレスポンスを返すことができます。
http.get('/api/users/:id', ({ params }) => {
const { id } = params
return HttpResponse.json({
id: Number(id),
name: `ユーザー${id}`,
email: `user${id}@example.com`
})
})
エラーレスポンスのモック
エラー状態のテストも簡単に行えます。
http.get('/api/users/:id', ({ params }) => {
const { id } = params
if (id === '999') {
return HttpResponse.json(
{ error: 'ユーザーが見つかりません' },
{ status: 404 }
)
}
// 通常のレスポンス
})
遅延レスポンス
ローディング状態のテストのために、意図的に遅延を追加できます。
import { delay } from 'msw'
http.get('/api/users', async () => {
await delay(2000) // 2秒遅延
return HttpResponse.json([
// データ
])
})
テスト環境での使用
Vitestでの設定例:
src/mocks/server.ts
を作成:
import { setupServer } from 'msw/node'
import { handlers } from './handlers'
export const server = setupServer(...handlers)
vitest.setup.ts
に以下を追加:
import { beforeAll, afterEach, afterAll } from 'vitest'
import { server } from './src/mocks/server'
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
テストファイルでの使用例:
import { describe, it, expect } from 'vitest'
import { server } from '@/mocks/server'
import { http, HttpResponse } from 'msw'
describe('ユーザー一覧', () => {
it('エラー時の処理を確認', async () => {
// このテストのみ500エラーを返すように上書き
server.use(
http.get('/api/users', () => {
return HttpResponse.json(
{ error: 'サーバーエラー' },
{ status: 500 }
)
})
)
// エラー処理のテスト
})
})
まとめ
MSWは、Service Worker APIを活用してネットワークレベルでAPIリクエストをモックする強力なツールです。開発環境でのAPIモッキングからテスト環境での使用まで、一貫した方法でAPIの振る舞いを制御できます。