📝

ReactにMSWを導入する手順

2022/04/20に公開

現在参画中のプロジェクトでは、Mock Service Worker(以下「MSW」)というものを使用しています。フロントエンド開発時に、

「仮でもいいからAPI叩いてデータ取得したいなー」

って場面はあると思いますが、
そういった場合に便利だと思ったので、ざっくり使い方をまとめています。
公式サイトを参考にさせて頂きました。
https://mswjs.io/

インストール

Create React App

公式のドキュメントでは、Create React App アプリケーションに導入していく手順で書かれているので、まずはReactのアプリケーションを新規作成します。

npx create-react-app my-app

MSWをインストール

続いて、mswをインストールします。

npm install msw --save-dev
# or
yarn add msw --dev

モックの定義

どのリクエストをモックするかを定義するために、 リクエストハンドラ関数を使用します。
この関数を使うと、メソッドやURL、その他の条件に基づいて任意のリクエストを捕捉し、どういったレスポンスを返すかを指定することができます。

MSWを使う場合、リクエストハンドラやブラウザ、サーバ固有の設定などの一覧をモック定義と呼びます。
モック定義の管理に厳密なルールはありませんが、APIモック関連のモジュールは1つのディレクトリにまとめておくことが望ましいです。

ディレクトリを作成します。

mkdir src/mocks

ディレクトリを作成したら、すべてのリクエストハンドラを格納するモジュールを作成します。

touch src/mocks/handlers.js

APIを選択する

MSWでAPIをモックする方法は、実際のアプリケーションでAPIがどのように使用されるかに類似しています。
モックを作りたいAPIの種類に応じて、手順が変わります。

  • REST API
  • GraphQL API

今回は、 REST APIを選択します。

REST APIをモック化する

src/mocks/handlers.js ファイルに、REST APIをモック化するために必要なものをインポートします。
これらは、ライブラリが公開しているrest名前空間の下にまとめられています。

handlers.js
import { rest } from 'msw'

Request handlerを実装する

REST APIのリクエストを処理するには、そのメソッドとパス、そしてモック化されたレスポンスを返す関数を指定する必要があります。

ここではユーザーにおける基本的なログイン・フローをモック化していきます。
下記の2つのリクエストを処理します。

  • POST /login:ユーザーがログインできるようにします。
  • GET /user:ログインしているユーザーに関する情報を返します。
handlers.js
import { rest } from 'msw'
export const handlers = [
  // /login へのPOSTリクエストを処理
  rest.post('/login', null),
  
  // /user へのGETリクエストを処理
  rest.get('/user', null),
]

Response resolverを実装する

インターセプトされたリクエストに応答するには、レスポンス・リゾルバ関数を使ってモックレスポンスを指定する必要があります。

レスポンスリゾルバは、以下の引数を受け付ける関数です。

  • req:一致するリクエストについての情報
  • res:モックのレスポンスを生成するための関数ユーティリティ
  • ctx:ステータスコード、ヘッダ、ボディなどを設定するための関数群

上で定義したリクエストハンドラに対してレスポンスリゾルバを実装します。

handlers.js
import { rest } from 'msw'

export const handlers = [
  rest.post('/login', (req, res, ctx) => {
    // ユーザーの認証をセッションに永続させる
    sessionStorage.setItem('is-authenticated', 'true')

    return res(
      // 200のステータスコードで応答する
      ctx.status(200),
    )
  }),

  rest.get('/user', (req, res, ctx) => {
    // ユーザーが認証されているかどうかを確認する
    const isAuthenticated = sessionStorage.getItem('is-authenticated')

    if (!isAuthenticated) {
      // 認証されていない場合、403エラーで応答する
      return res(
        ctx.status(403),
        ctx.json({
          errorMessage: 'Not authorized',
        }),
      )
    }

    // 認証された場合、模擬ユーザの情報を返す
    return res(
      ctx.status(200),
      ctx.json({
        username: 'admin',
      }),
    )
  }),
]

統合する

ブラウザ環境とNode環境で同じリクエストハンドラを共有することができます。
NodeではService Workerを動かすことができないため、環境に応じて統合の仕方が異なります。
今回はブラウザ環境で動かします。

セットアップ

MSWは、リクエストのインターセプトを担当するService Workerを登録することで、クライアントサイドで動作します。しかし、Workerのコードを自分で書く必要はなく、ライブラリが配布しているWorkerファイルをコピーして使います。MSWは専用のCLIを提供しているので、それを使用します。

Mock Service Worker CLIのinitコマンドを実行します。

npx msw init <PUBLIC_DIR> --save

<PUBLIC_DIR> プレースホルダーを、公開ディレクトリへの相対パスに置き換えます。
Create React App プロジェクトでは、このコマンドは次のようになります。

npx msw init public/ --save

workerを設定する

モックの定義ディレクトリ(src/mocks)に、Service Workerの設定と起動を行うファイルを作成します。

touch src/mocks/browser.js

browser.js ファイルで、上で定義したリクエストハンドラを使ってワーカーのインスタンスを作成します。

browser.js
import { setupWorker } from 'msw'
import { handlers } from './handlers'

// 指定されたリクエストハンドラを持つサービスワーカーを設定する
export const worker = setupWorker(...handlers)

workerをスタートする

モック定義を実行するためには、アプリケーションのコードにインポートする必要があります。
モックは開発向けの技術なので、環境に応じて src/mocks/browser.js ファイルを条件付きでインポートする必要があります。

src/mocks/browser.js ファイルを、以下の例のように条件付きでインポートします。

index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'

if (process.env.NODE_ENV === 'development') {
  const { worker } = require('./mocks/browser')
  worker.start()
}

ReactDOM.render(<App />, document.getElementById('root'))

確認と検証

モック定義をインポートすると、ブラウザのコンソールにMSWからのアクティベーション成功のメッセージが表示されます。

これで定義されたハンドラにマッチするリクエストはインターセプトされ、モック化されるようになりました。

参考

https://mswjs.io/

まとめ

以上、MSWのをReactで使用する手順でした。
別のプロジェクトに参画した際など、状況に応じて導入してみたいと思います。

Discussion