「Mock Service Worker」は、Service Workerを利用したモックライブラリです。 「REST API」「GraphQL API」の両方をサポートしています。ここでは、ReactアプリにMock Service Workerを導入する方法を確認します。
目次
インストール
create-react-app
でReactプロジェクトを生成します。
npx create-react-app my-app --template typescript
cd my-app/
Mock Service Worker
をインストールします。
yarn add msw --dev
バージョンは以下の通りです。
$ yarn info msw | grep 'version:'
version: '0.21.3',
フォルダ構造・コード
フォルダ構造
今回、以下フォルダ構造で実装しました。
├──public
│ ├── index.html
│ └── mockServiceWorker.js // コマンド(npx msw init public/)で生成したファイル
└──src
├── mocks
│ ├── browser.ts // ワーカーインスタンスを作成
│ ├── handlers.ts // 「リクエストパス」と「リクエストに応答する関数」を紐付け
│ └── resolvers
│ └── mockUser.ts // リクエストに応答する関数
├── App.tsx // fetchを行うサンプルコンポーネント
└── index.tsx // ワーカーインスタンスをアプリケーションのコードにインポート
src/App.tsx
動作確認用コードです。
import React, { FC, useEffect, useState } from 'react';
export type User = {
id: number;
username: string;
age: number;
};
const isUser = (params: unknown): params is User => {
const user = params as User;
return (
typeof user?.id === 'number' &&
typeof user?.username === 'string' &&
typeof user?.age === 'number'
);
};
const statusValues = {
Loading: 'loading',
Success: 'success',
Error: 'error',
} as const;
type Status = typeof statusValues[keyof typeof statusValues];
const App: FC = () => {
const [user, setUser] = useState<User | null>(null);
const [status, setStatus] = useState<Status>(statusValues.Loading);
useEffect(() => {
const load = async (): Promise<void> => {
try {
const response = await fetch('http://localhost:3001/v1/users/123');
if (!response.ok) {
throw new Error(`HTTP-Error: ${response.status}`);
}
const responseData = (await response.json()) as unknown;
if (!isUser(responseData)) {
throw new Error(`Response Invalid: ${JSON.stringify(responseData)}`);
}
setUser(responseData);
} catch (err) {
setStatus(statusValues.Error);
throw err;
} finally {
setStatus(statusValues.Success);
}
};
void load();
}, []);
if (status === statusValues.Loading) return <p>Loading...</p>;
if (status === statusValues.Error) return <p>Error</p>;
return (
<>
<p>id: {user?.id}</p>
<p>username: {user?.username}</p>
<p>age: {user?.age}</p>
</>
);
};
export default App;
fetchした際、モックデータが返されるように実装していきます。
src/mocks/resolvers/mockUser.ts
リクエストに応答する関数を記述しています。
import { ResponseResolver, MockedRequest, restContext } from 'msw';
import { User } from 'App';
const mockUser: ResponseResolver<MockedRequest, typeof restContext> = (req, res, ctx) => {
const userId = Number(req.params.userId);
const user: User = {
id: userId,
username: 'wakuwaku bank',
age: 18,
};
return res(ctx.json(user));
};
export default mockUser;
src/mocks/handlers.ts
mockUser.ts
をインポートして、リクエストパスと紐づけています。
import { rest } from 'msw';
import mockUser from 'mocks/resolvers/mockUser';
const handlers = [
rest.get('/v1/users/:userId', mockUser),
];
export default handlers;
src/mocks/browser.ts
handlers.ts
をインポートして、ワーカーインスタンスを作成しています。
import { setupWorker } from 'msw';
import handlers from 'mocks/handlers';
const worker = setupWorker(...handlers);
export default worker;
src/index.tsx
開発環境のときだけ worker.start()
します。
import React from 'react';
import ReactDOM from 'react-dom';
import App from 'App';
import worker from 'mocks/browser';
if (process.env.NODE_ENV === 'development') {
void worker.start();
}
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root'),
);
動作確認
yarn start
で起動して動作確認します。モックデータは Service Worker
によって返されるので、別途専用のモックサーバーを起動する必要はありません。
モックサービスワーカーがactivateされたら、[MSW] Mocking enabled.
と表示されます。
ネットワークタブです。Service Worker
を利用しているので、from ServiceWorker
と表示されます。
Service Worker
のイベント監視はコマンド( npx msw init public/
)で生成したpublic/mockServiceWorker.js
で実装されています。
参考・関連
- Service Worker
- Mock Service Worker