msw×Next.js（PageRouter）

# msw
APIリクエストをインターセプトしてモックデータを返したりすることができるパッケージです。
今回はREST API（Fetch APIを利用）想定で進めます。

## src/mocks/handlers.js
```react
// src/mocks/handlers.js
import { http } from 'msw'
 
export const handlers = [
  http.get('https://jsonplaceholder.typicode.com/todos/1', () => {
    console.log('Captured a "GET https://jsonplaceholder.typicode.com/todos/1" request')
  }),
  http.post('/posts', () => {
    console.log('Captured a "POST /posts" request')
  }),
  http.delete('/posts/:id', ({ params }) => {
    console.log(`Captured a "DELETE /posts/${params.id}" request`)
  }),
]
```
参照：https://mswjs.io/docs/network-behavior/rest

### リクエストハンドラ
```react
  http.get('/posts', () => {
    console.log('Captured a "GET /posts" request')
  }),
```````
参照：https://mswjs.io/docs/network-behavior/rest

### レスポンスリゾルバ
HttpResponse部分のこと
```react
  http.get('/posts', () => {
    return HttpResponse.json(Array.from(allPosts.values()))
  }),
``````
参照：https://mswjs.io/docs/network-behavior/rest

### リクエスト本文を読み取る
request本文を読み取る
request.json()はPromiss型を返すためawaiが必要
request.json() は、リクエストのボディを JSON 形式として解析するためのメソッド
```react
http.post('/posts', async ({ request }) => {
    const newPost = await request.json()

    allPosts.set(newPost.id, newPost)

    return HttpResponse.json(newPost, { status: 201 })
}),
```
参照：https://mswjs.io/docs/network-behavior/rest

### パスパラメータの読み取り
リクエストパス内の１つのセグメント内でパラメーターを読み取る
「/posts/[任意の値]」があれば引っかかるようになる

```react
  http.delete('/posts/:id', ({ params }) => {
    const { id } = params
 
    const deletedPost = allPosts.get(id)
 
    if (!deletedPost) {
      return new HttpResponse(null, { status: 404 })
    }
 
    allPosts.delete(id)
 
    return HttpResponse.json(deletedPost)
  }),
```
参照：https://mswjs.io/docs/network-behavior/rest
 
## mockServiceWorker.js


```
npx msw init ./public --save
```

実行するとpackage.jsonに登録される。
mockServiceWorker.jsの保存先が登録され読み込みが行われる。
```yml
{
  "name": "my-app",
  "msw": {
    "workerDirectory": "./public"
  }
}
```
参照：https://mswjs.io/docs/cli/init

## src/mocks/browser.ts
### Browser integration
フロントサイドでモックサーバーを起動する
```react
import { setupWorker } from 'msw/browser'
import { handlers } from './handlers'

export const worker = setupWorker(...handlers)
```
参照：https://mswjs.io/docs/integrations/browser

## src/mocks/server.ts
### Node.js integration
SSR
```react
import { setupServer } from 'msw/node'
import { handlers } from './handlers'

export const server = setupServer(...handlers)
```
参照：https://mswjs.io/docs/integrations/node

## pages/_app.tsx
フロントサイドかサーバーサイドかの判定が必要
これはmswのissueにも問題が上がってた対策です

https://github.com/mswjs/msw/issues/1877#issuecomment-1857507825

開発環境のみで動くようにすることも必要（process.env.NODE_ENV）

```react
if (process.env.NODE_ENV === 'development') {
  if (typeof window !== 'undefined') {
    import('../mocks/browser').then(({ worker }) => {
      worker.start()
    });
  }else{
    import('../mocks/server').then(({ server }) => {
      server.listen()
    });
  }
}
```

### 起動確認
```
npm run dev
```

これが出てきていればOK
![スクリーンショット 2024-10-20 18.22.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/943982/a6227060-3814-38df-1c47-17bacb7d5af9.png)


## pages/index.tsx
index.tsxでインターセプトするURLをfetchで呼び出してみましょう
```react
const test = async () => {

    await fetch("https://jsonplaceholder.typicode.com/todos/1");
    return;
};
```

コンソールログに結果が出ていればOK
![スクリーンショット 2024-10-20 18.26.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/943982/3832b123-bda8-0687-d1c6-1c5228dda6b2.png)


## おまけ
今回はPageRouterなので検証していないが、appRouterの場合はこちらにexampleがあります（まだDraftですが・・・）

https://github.com/mswjs/examples/pull/101