🦆

Mock Service Worker で開発用のモックAPIを作る

4 min read

フロントエンドの開発時に仮の API を使いたいってシチュエーションはわりとあると思います。
そんな時に、Mock Service Worker を使うと便利だったのでまとめます。

Mock Service Worker とは?

Mock Service Worker は、ネットワークレベルで API リクエストをインターセプトして mock のデータを返すためのライブラリです。API リクエストを含む処理のテストや、開発時の mock サーバーの代替として利用出来ます。

https://mswjs.io/

テストでの利用については以前こちらの記事でまとめました。

https://zenn.dev/ryo_kawamata/articles/introduce-mock-service-worker

今回は開発時のモック API としての利用について書きます。

開発用の API というと、JSON Serverが有名ですが、Mock Service Worker では Service Worker を使ってリクエストを返すため、別プロセスでローカルサーバーを立てる必要もなく手軽に利用できます。

仕組みは公式のこちらのビデオがわかりやすいです。

https://youtu.be/HcQCqboatZk

Mock Service Worker での開発用APIの立て方

Vite で作った Vue のプロジェクトで利用する場合を例にまとめます。

パッケージの追加

Mock Service Worker のパッケージをプロジェクトに追加します。

$ yarn add -D msw

Service Workerのコードを生成

Mock Service Worker は Service Worker で API リクエストをインターセプトします。その Service Worker のコードをプロジェクトの公開ディレクトリに追加します。
ファイルは Mock Service Worker の提供する CLI を使って生成できます。

$ npx msw init public/ --save

Vue プロジェクトの公開ディレクトリは./publicなのでそちらを指定しています。

コマンドを実行すると public 配下に mockServiceWorder.js が追加されるはずです。

public/
├── favicon.ico
└── mockServiceWorker.js # 追加

mockServiceWorder.jsでは、Service Worker でのイベント処理が書かれています。

モック API の定義を追加

プロジェクトの src 配下にmockディレクトリを作成し、そこにhandler.jsbrowser.jsを追加します。

handler.jsでは、どの URL のリクエストに対して、どのようなレスポンスを返すのかを定義しています。

src/handler.js
import { rest } from 'msw'

export const handlers = [
  rest.get('/users', (req, res, ctx) => {
    return res(
      ctx.status(200),
      ctx.json([
        {
          id: 1,
          name: 'foo',
        },
        {
          id: 2,
          name: 'bar',
        }
      ]),
    )
  }),
]

browser.js では handler.js で作成した定義をもとに Service Worker のセットアップを行っています。

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

export const worker = setupWorker(...handlers)

今回は REST API のモックのコードを例にあげていますが、Mock Service Worker では GraphQL の API でもモック可能です。
https://mswjs.io/docs/api/graphql

Service Workerのスタート処理の追加

これまでの作業で準備が出来たので、プロジェクトのエントリーポイントに Service Worker のスタート処理を追加します。

Vue のmain.jsに追記する例です。

src/main.js
import { createApp } from 'vue'
import App from './App.vue'

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

createApp(App).mount('#app')

開発ビルドの場合のみ、Worker を起動しています。
これでプロジェクトのスタート時にモックが動作するようになります。

worker.start()は非同期処理です。モック対象の API を呼ぶタイミングによっては Service Worker の起動前に呼ばれてしまい、リクエストのインターセプトが動作しない場合もあります。その場合は以下 URL の Deferred mounting を試すと良さそうです。
https://mswjs.io/docs/recipes/deferred-mounting

モックの動作確認

実際にモックの動作を確認します。

App.vue に/usersの API を呼び出す処理を追加してみます。

components/App.vue
<template>
  <h1>Users</h1>
  <ul>
    <li v-for="user in users" :key="user.id">
      id: {{user.id}}, name: {{user.name}}
    </li>
  </ul>
</template>

<script lang="ts">
import { ref, defineComponent, onMounted } from 'vue'

type User = {
  name: string;
  age: number
}

export default defineComponent({
  name: 'App',
  setup() {
    const users = ref<User[]>([])

    onMounted(async () => {
      const res = await fetch('/users')
      users.value = await res.json()
    })

    return { users }
  }
})
</script>

yarn devで Vue の開発サーバーを起動し、localhost にアクセスし DevTools を開くと Console に Mocking enabled と表示されるはずです。これが Mock Service Worker によるモックが動作していることを示します。

また、DevTools の Network を確認すると、Service Worker にインターセプトされた/usersへのリクエストが確認出来るはずです。

レスポンスを見ると handler.js で定義した値が返却されています。

ページも問題なく描画されます。

参考

終わりに

以上、開発時の API リクエストのモック処理での Mock Service Worker の利用例でした。
別で開発サーバーのプロセスを立てるより、手軽にモックの API を使えるようになるのでとても良い感じだなと思いました。今後も使っていきたいです。

Discussion

ログインするとコメントできます