概要
- サーバサイドAPIはまだ実装されてないけど、Webフロントエンドの実装を進めたい
- 顧客に見せるために作成したモックの実装を、できるだけ実際の実装に流用したい
- E2Eテストの為だけにビジネスロジックとは関係のない実装を入れたくない
- Mock Service Workerを使えばそんなお悩みを解決できます
Mock Service Workerとは
Service Worker APIを利用してブラウザのリクエストをインターセプトすることで、サーバサイトAPIの振る舞いを模倣するモックを構築できるフレームワークです。JSON Serverのようなモックサーバフレームワークとの違いは、単独のサーバを起動するのではなく、Service Workerを常駐してブラウザのリクエストのインターセプトすることでモック用のレスポンスを返却する仕組みになっている点です。
準備
React用のサンプルが用意されているので、今回はそれを使用して挙動を見ていきたいと思います。
Mock Service Worker (以下MSW) のExamplesに記載されているインストール手順に従ってローカルに環境を構築します。
$ git clone https://github.com/mswjs/examples.git
$ cd examples
$ yarn
$ cd rest-react
$ yarn start
サービスが起動しました。
ブラウザから http:/localhost:3001 にへアクセスするとデモ画面が表示されます。
動かしてみる
usernameを入力するとログインAPIが実行されて、そのレスポンス内容が画面に表示されるというデモになります。
usernameを入力してSubmitボタンを押してみます。
ユーザー情報が画面に表示されました。この値はMSWによって実行されているログインAPIのモックから返却されたものになります。
でも せっかく入力した username が画面に表示されていません。
コードを読み進めてゆくついでに画面に username が表示されるようにしていこうと思います。
MSWの実行
デモのReactプロジェクトでは examples/rest-react/src/index.js の中でMSWを実行しています。このわずか数行の実装でブラウザからのリクエストがMSWへインターセプトされるようになります。
// Start the mocking conditionally.
if (process.env.NODE_ENV === 'development') {
const { worker } = require('./mocks/browser')
worker.start()
}
Reactのfetch処理
ReactではログインAPIをfetch APIでリクエストしています。ホストを指定していないので、ログインAPIは同ホスト内で実行してされている想定となっています。
JSON Serverなどを使用する場合はfetch APIに指定するホストなどを挿げ替える判定処理を施したりしますが、冒頭に記載した通りMSWではそのような必要はありません。
examples/rest-react/src/LoginForm.js
// Handle a submit event of the form
const handleFormSubmit = useCallback(
(event) => {
// Prevent the default behavior, as we don't want
// for our page to reload upon submit.
event.preventDefault()
// Perform a POST /login request and send the username
fetch('/login', {
method: 'POST',
body: JSON.stringify({
username,
}),
})
.then((res) => res.json())
// Update the state with the received response
.then(setUserData)
},
[username],
)
MSW のコード
examples/rest-react/src/mocks 以下にMSWに関するソースコードが格納されています。
モックAPIの実態は handlers.js に実装されています。
/login というエンドポイントへpost methodでリクエストされた場合に、固定のJSONを返却するという処理になります。ちなみにこのコードには画面から入力された username を正しく取得できないバグがあるので、後ほど修正していきたいと思います。
examples/rest-react/src/mocks/handlers.js
import { rest } from 'msw'
export const handlers = [
rest.post('/login', (req, res, ctx) => {
const { username } = req.body
return res(
ctx.json({
id: 'f79e82e8-c34a-4dc7-a49e-9fadc0979fda',
username,
firstName: 'John',
lastName: 'Maverick',
}),
)
}),
]
username を画面に表示できるようにしてみる
前述の通り、ソースコードにはバグがあるので username がレスポンスでundefinedになってしまいまうため、コードを少々修正します。
examples/rest-react/src/mocks/handlers.js
Before
const { username } = req.body
After
const { username } = JSON.parse(req.body)
次に画面にレスポンスで取得した username を表示するようにしてみます。
examples/rest-react/src/LoginForm.js
Before
if (userData) {
return (
<div>
<h1>
<span data-testid="firstName">{userData.firstName}</span>{' '}
<span data-testid="lastName">{userData.lastName}</span>
</h1>
<p data-testid="userId">{userData.id}</p>
</div>
)
}
After
if (userData) {
return (
<div>
<h1>
<span data-testid="firstName">{userData.firstName}</span>{' '}
<span data-testid="lastName">{userData.lastName}</span>
</h1>
{/** 入力した username を表示してみる */}
<p data-testid="username" style={{ color: 'red' }}>
{userData.username}
</p>
<p data-testid="userId">{userData.id}</p>
</div>
)
}
実行してみる
usernameを入力してSubmitボタンを押してみます。
ログイン後の画面に入力した username が赤文字で表示されました。
最後に
今回はMSWのデモを利用して簡単な仕組みを見ていきました。MSWを使用することでクライアントアプリケーションのコードに変更を加えることなくサーバサイドのモックと連携できることがわかりました。
次回は同デモを使ってE2Eテストの実装を見ていきたいと思います。
参考