こんにちわ、SMLでエンジニアをしている@kawakami0717です。2年後のLAマラソンに出るために日々走る毎日ですが、最近新しくHOKA のシューズを買いました。HOKAはランニングメーカーで、デザイン性、クオリティ、厚底などに特徴があります。是非何かの参考になれば嬉しいです。
Mock Service Workerとは、REST APIリクエストをService Workerが中断して、用意したモックを返すことのできるライブラリです。新機能開発時など、まだREST APIが整っていない時でも、モック用に仮のソースコードを書かなくても、本来のソースコードで動作できる大変便利なライブラリです。また、REST APIの他にもGraphQL APIもモックすることができます
公式サイトはこちら https://mswjs.io/
Mock Service Workerは以下のようなモック定義ファイルを作成して使います。以下の rest.get
の引数に「モックするリクエストPATH」と「モックデータ」を記述します。モックデータは res
の引数にステータスコードとモックデータを記述します
// mocks/handlers.js
import { rest } from 'msw'
export const handlers = [
rest.get('/user', (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
username: 'admin',
}),
)
}),
]
モック定義ファイルを作成すると、定義したAPIリクエストが発生したときにService Workerがリクエストを中断させモックデータを返すようになります。ステータスコードも定義することができ、本来のAPIリクエストが返ってきたように振るまうことができます。 モックする必要が無くなった場合は、handlersからモック定義を削除します。もし変更しても変わらない場合は、Service Workerのキャッシュが残っている可能性があるので、Dev ToolsのApplicationを開いてService WorkerをUnregisterしてください
以下のコマンドを実行してmswをインストールします
$ npm install msw --save-dev
# or
$ yarn add msw --dev
次にモックの定義ファイルを保存するディレクトリを作ります。好きな場所に作成しても大丈夫ですが以下のように作成するのがおすすめです
$ mkdir mocks
次に作成したディレクトリにhandlerファイルを作成します。このhandlerファイルに上記で紹介したモックの定義を書きます
$ touch mocks/handlers.js
/user
リクエストを中断させて {username: 'admin'}
を返すように定義する場合は、 handlers.js
に以下のように書きます。
import { rest } from 'msw'
export const handlers = [
rest.get('/user', (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
username: 'admin',
}),
)
}),
]
次にService Workerの設定と起動を行うファイルを作成します
$ touch mocks/browser.js
browser.js
を以下のように記述します。setupWorkerでモック定義を読み込みworkerインスタンスを作成しています
// src/mocks/browser.js
import { setupWorker } from 'msw'
import { handlers } from './handlers'
// This configures a Service Worker with the given request handlers.
export const worker = setupWorker(...handlers)
Service Workerに登録するセットアップファイルを配置します。このファイルは公開ディレクトリ直下に配置します。Nuxt2の場合は static
配下に配置します。その他の環境で扱いたい場合は、公式サイトを参考にしてください。
Nuxt2にセットアップファイルを配置するには以下のコマンドを実行します
$ npx msw init static/ --save
Mock Service Workerを動作させるには、workerを起動する必要があります。Nuxtが起動した時にworkerを起動させるためにpluginを作成します
$ touch plugins/mock.ts
mock.ts
は下記のように記述します。js環境の場合は適宜読み替えてください
export default () => {
if (process.env.NODE_ENV === 'development') {
const { worker } = require('../mocks/browser')
worker.start()
}
}
注意:Mock Service Workerは開発環境だけ起動するようにすることをお勧めします。プロダクション環境で使うとユーザーにとって良くないエクスペリエンスになることがあります。 作成したpluginをnuxt.configに定義します
plugins: [
{ src: '@/plugins/mock', mode: 'client' }
],
Nuxtを起動させるとMock Service Workerが起動しブラウザのコンソールに以下のメッセージが表示されます。
> [MSW] Mocking enabled
メッセージが表示されない場合は、Service Workerが動いていないことが考えられますので、以下を読み進めてください(エラーの詳細を知りたい場合は、 plugins/mock.ts
の worker.start()
が結果を返すので、その結果から確認できます)
Servce WorkerはTLS環境以外では起動しません。また、自前で発行した自己署名証明書(オレオレ証明)でも信用がないため起動しません。これを解決するためにはRoot CAで証明を得たTLSを用意する必要があります。
ローカル環境のTLSとは、 127.0.0.1
が設定されたドメインに対するTLSを指します。TLSの発行にコストをかけたくない場合はLet's Encryptを利用すると無料でRoot CA証明されたTLSを取得することができます。
Let's EncryptでlocalhostのTLSの発行から設定までを雑に紹介します
privkey.pem
fullchain.pem
をサーバーに設定する詳しい方法知りたい方はこちらの記事をご覧ください(Let's Encrypt以外でも mkcert を使ってTrustedなTLSを発行できますが、昨今のOSSで起きた事件などを考えると、悪意のあるコードを仕込まれる可能性も否定できないため、特にTLSの発行についてはOSSの利用は避けたいところです)
このローカル環境のTLSの運用方針については、Jxckさんの記事を参考にさせていただくと以下が考えられます
発行した privkey.pem
fullchain.pem
を以下のようにnuxt.configに設定します
export default {
...
server: {
https: {
key: fs.readFileSync(path.resolve(__dirname, 'server/privkey.pem')),
cert: fs.readFileSync(path.resolve(__dirname, 'server/fullchain.pem')),
},
},
}
Nuxt2を起動しhttpsとlocalhostのドメインでアクセスして、以下のメッセージがコンソールに表示されると成功です
> [MSW] Mocking enabled
モック定義したAPIをリクエストして定義したモックデータが返ってきていることを確認してください。
Dev ToolsのNetworkから、そのデータはMock Service Workerで返されたデータなのかを確認することができます。APIのリクエストのヘッダーに x-powered-by: msw
と記載がある場合はMock Service Workerから返されたレスポンスになります
Mock Service Workerは、REST APIリクエストをService Workerが中断してモックを返すライブラリです。これまでは、API開発を待つかソースコードに仮の実装を入れるなで対応するケースが多いかと思いますが、Mock Service Workerを使うことでAPI開発を待つことなく、ソースコードも仮の実装を入れることなく開発が行うことができます。 Service Workerを使う上でTrustedなTLSを用意するのは少し面倒ですが、自己署名TLSと信頼されたTLSではブラウザの挙動も変わることを踏まえても、この際に切り替えても良いのではと思います。 いずれにせよ、大変面白い仕組みなのとソースコードの品質向上にもつながるライブラリなので是非何かの参考にしていただけたらと思います。