mswを使って、requestをinterceptしてmocked responseする！

mswはAPIモーキングライブラリで、サーバーに向けたネットワーク要求をインターセプトして模擬応答(mocked response)を返す役割を果たします。

下の写真は、ブラウザがrequestを送るとservice workerがキャッチして、MSWを通してモッキングされたレスポンスをブラウザに送ります。
実際は、実物のAPIサーバからレスポンスを受けるが正しいだが、MSWを使ってリクエストをキャッチして任意のレスポンスを返すことができます。
そのrequestは実際のサーバーではないmswに送った後、登録された<b>handler</b>を通じて模擬応答をクライアントに送ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3097775/4b440abd-27bc-1f50-3c36-11ce02dc0633.png)

<h2>msw setup</h2>

```terminal:msw package install
npm install msw --save
```

```terminal:service worker登録
npx msw init public/ --save
```
publicのフォルダにmockServiceWorkerファイルを生成してくれるcommandです。
/public/mockServiceWorker.jsとは、ファイルができ、そのファイルがサービス・ウォーカーにmockサーバーを登録させます。このファイルはネットワークの要求をinterceptできるように設計されたservice worker apiを活用します。


<h2>browser.js定義</h2>

setupWorker()関数を使用してservice workerを生成します。関数の買収はhandler.jsに定義したハンドラを渡します。
```react:src/mocks/browser.js
import { setupWorker } from 'msw'
import { handlers } from './handlers'

export const worker = setupWorker(...handlers); //定義handler登録
```


<h2>handlers.js定義</h2>

handlers.jsは要求が入って来た時、模擬の回答をしてくれるハンドラ(handler)コードを作成しなければなりません。
下のコードは、login requestと...raw.githubu...requestをinterceptしてmockingしています。
```react:src/mocks/handlers.js
import { rest } from 'msw'

export const handlers = [
    rest.get('/login', async (req, res, ctx) => {
            return res(
      ctx.json({
        id: 'f79e82e8-c34a-4dc7-a49e-9fadc0979fda',
        firstName: 'John',
        lastName: 'Maverick',
      })
    )
    }),
    rest.get('https://raw.githubusercontent.com/techoi/raw-data-api/main/simple-api.json', async (req, res, ctx) => { // interceptするURLを入力！
        return res(
          {
	"data": {
		"people" :
		[
			{
				"name": "jung",
				"age": 135
			},
			{
				"name": "yeounjae",
				"age": 13
			},
			{
				"name": "cindy",
				"age": 15
			},
			{
				"name": "judy",
				"age": 25
			},
			{
				"name": "marry",
				"age": 64
			},
			{
				"name": "tommy",
				"age": 109
			}
		]
	}
}
            )
        )  
    })
]
```

<h2>index.js定義</h2>
index.jsにはweb applicationが実行されるとき、service workerも実行されるようにしたコードを追加します。

```react:src/index.js
// Start the mocking conditionally.
// service mockを実行されるコード！
if (process.env.NODE_ENV === 'development') {
  const { worker } = require('./mocks/browser')
  worker.start()
}
```

<h2>Mockingテスト</h2>

```react:TestMocking.jsx
import React, {useState} from 'react'
const Item = ({ name, age }) => {
    return (
        <li>
            name : {name} /age : {age}
        </li>
    );
}
const url =
    "https://raw.githubusercontent.com/techoi/raw-data-api/main/simple-api.json";
export default function TestMocking() {
    const [data, setData] = useState(null);
    const [error, setError] = useState(null);

    const handleClick = () => {
        fetch(url)
            .then((response) => {
                return response.json();
            })
            .then((json) => {
                setData(json.data);
            })
            .catch((error) => {
                setError(`something wrong: ${error}`);
            })
    }

        const handleClick2 = () => {
            fetch('/login')
                .then((response) => {
                    return response.json()
                })
                .then((json) => {
                    console.log(JSON.stringify(json));
                })
    }
    if (error) {
        return <p>{error}</p>
    }
    return (
        <div>
            <button onClick={handleClick}>データ呼び出し1</button>
            <button onClick={handleClick2}>データ呼び出し2</button>
            {data && (
                <ul>
                    {data.people.map((person) => (
                        <Item
                            key={`${person.name}-${person.age}`}
                            name={person.name}
                            age={person.age}
                        />
                    ))}
                </ul>
            )
            }
        </div>
    );
}
```
「データ呼び出し1」ボタンを押下すると、変数urlを fetchします。
変数urlのJson値は以下になります。
```json:https://raw.githubusercontent.com/techoi/raw-data-api/main/simple-api.json
{
	"data": {
		"people" :
		[
			{
				"name": "jimmy",
				"age": 135
			},
			{
				"name": "timmy",
				"age": 13
			},
			{
				"name": "cindy",
				"age": 15
			},
			{
				"name": "judy",
				"age": 25
			},
			{
				"name": "marry",
				"age": 64
			},
			{
				"name": "tommy",
				"age": 109
			}
		]
	}
}
```
しかし！handerls.jsに変数url requestに対してintercept定義しておいたため、結果は以下になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3097775/f451ebdb-fa0f-c2ac-abdf-127f89b8dca7.png)