🧑💻
#163 UIからAPIモックレスポンスをリアルタイム切り替え
はじめに 〜なぜUIからモックを切り替えるのか〜
フロントエンド開発では「APIモック」が欠かせません。しかし、従来のモックでは下記のような課題に直面することがあります。
- 異常系の再現に手間がかかる
- モックの状態変更にリビルドが必要
- テストごとに異なる挙動を切り替えたいが面倒
- 非エンジニアが自分で異常系を試せない
本記事では、UIからAPIモックレスポンスをリアルタイムで切り替える手法を紹介します。この仕組みにより、エンジニア・QA・デザイナー問わず、誰でも異常系挙動を即座に再現・検証できるようになります。
APIモックとMSWの基礎知識
なぜAPIモックが必要か?
- バックエンド未完成でもUI開発を進めたい
- エラー系や異常系を検証したい
- E2EテストやCI/CDでも異常系の動作を確認したい
従来のAPIモックの課題
- モック切り替えにコード編集+ビルドが必要
- 状態の永続性がなく、毎回手動設定
- QAエンジニアやPdMなど非開発者が自由に操作できない
- ⇒バックエンドの開発が終わっていない場合や本番環境APIの利用に課金や制限がある場合、安定したテストを実施するためにQAでもモックAPIが使われることがあります。
MSW(Mock Service Worker)とは
- Service Workerを活用し、実際のネットワーク通信を横取りしてモックレスポンスを返す
- REST/GraphQL両対応、Node.js/Jest環境でも同じハンドラが使える
- 本番に近い形でのUI/UX検証・自動テストが可能
- 公式ドキュメント
UIからAPIモックを切り替える設計思想
1. 状態管理
- localStorageやグローバル変数に状態を保存
- リロード後もエラー状態が保持される
- SSRやNode.js環境ではメモリやファイルで代用可能
2. MSWハンドラとの連携
- 現在のエラー状態に応じてMSWハンドラのレスポンスを分岐
- 異常系だけでなく、ネットワーク切断やタイムアウトも再現
3. UI/UX設計
- 誰でも使えるモック切り替えパネル
- 操作ミス防止のためのクリアボタン・確認導線
- 状態がリアルタイムで反映される設計
4. セキュリティ・運用上の工夫
- 本番ではUIパネル・モック動作を完全無効化
- window直下の状態のみ操作可能にして不正アクセスを防止
実装サンプル
1. モック状態管理クラス
mockErrorState.ts
export type MockErrorType = number | 'network' | 'timeout' | null;
class MockErrorStateManager {
private state: Record<string, MockErrorType> = {};
setError(endpoint: string, error: MockErrorType) {
this.state[endpoint] = error;
localStorage.setItem('MOCK_ERROR_STATE', JSON.stringify(this.state));
}
getError(endpoint: string): MockErrorType {
return this.state[endpoint] || null;
}
clearError(endpoint: string) {
delete this.state[endpoint];
localStorage.setItem('MOCK_ERROR_STATE', JSON.stringify(this.state));
}
getAllErrors() {
return { ...this.state };
}
}
export const mockErrorState = new MockErrorStateManager();
2. MSWのハンドラで分岐制御
handler.ts
import { rest } from 'MSW';
import { mockErrorState } from './mockErrorState';
export const handlers = [
rest.get('/api/items', (req, res, ctx) => {
const error = mockErrorState.getError('/api/items');
if (error === 404) return res(ctx.status(404), ctx.json({ error: 'Not Found' }));
if (error === 'network') return res.networkError('Network error');
if (error === 'timeout') return res(ctx.status(408), ctx.json({ error: 'Timeout' }));
return res(ctx.status(200), ctx.json({ items: [{ id: 1, name: 'Item A' }] }));
}),
];
3. モック切り替えUIパネル
MockErrorPanel.tsx
import React, { useState } from 'react';
import { mockErrorState } from '../mocks/mockErrorState';
const endpoints = ['/api/items', '/api/users'];
export const MockErrorPanel = () => {
const [errors, setErrors] = useState(mockErrorState.getAllErrors());
const setError = (endpoint: string, error: any) => {
mockErrorState.setError(endpoint, error);
setErrors(mockErrorState.getAllErrors());
};
return (
<div style={{ position: 'fixed', bottom: 20, right: 20, background: '#fff', border: '1px solid #ccc', padding: 16, zIndex: 1000 }}>
<h4>Mock Error Panel</h4>
{endpoints.map((ep) => (
<div key={ep} style={{ marginBottom: 8 }}>
<span>{ep}</span>
<button onClick={() => setError(ep, 404)}>404</button>
<button onClick={() => setError(ep, 500)}>500</button>
<button onClick={() => setError(ep, 'network')}>Network</button>
<button onClick={() => setError(ep, 'timeout')}>Timeout</button>
<button onClick={() => setError(ep, null)}>Clear</button>
</div>
))}
</div>
);
};

4. 拡張ポイント
- 通常系レスポンスもパネルから切り替え可能にする
- エンドポイント一覧を動的に取得+フィルタ検索を追加
まとめ
UIからモックレスポンスをリアルタイムに切り替えられると、以下のようなメリットがあります。
- 開発のスピードがアップする
- 異常系のテストも自動化しやすくなる
- エンジニアだけでなく、QAやPdMなども作業がしやすくなる
- 状態を保存できるので、問題の再現がラクになる
ぜひ本記事を参考に、MSWを活用したUI型モックを導入してみてください。
最後まで読んでいただきありがとうございます。
Discussion