Ⓜ️

msw用のAPIサーバーを立てた快適ローカル開発

2024/11/16に公開

やること

Expressサーバーでmswのhandlerを、別のポートのAPIとして叩けるようにする

必要なパッケージの導入

  • msw
  • @mswjs/http-middleware
  • cors
  • express
  • @types/cors
  • @types/express
  • tsx
npm i -D -E msw @mswjs/http-middleware @types/cors @types/express cors express tsx

実装

handlersの定義

src/mocks/handlers.ts

const handler1 = () => {
  return http.get('*/handler1', async () => {
    return new HttpResponse(
      JSON.stringify({ number: 1, string: 'string', boolean: true }),
      {
        status: 200,
      },
    )
  })
}

export const handlers = [handler1]

Expressサーバーの準備

src/mocks/expressServer.ts
import { createMiddleware } from '@mswjs/http-middleware'
import cors from 'cors'
import express from 'express'

import { handlers } from './handlers'

const app = express()
const PORT = 9999

app.use(cors())
app.use(express.json())

// MSWのハンドラーをExpressミドルウェアとして使用
app.use(createMiddleware(...handlers))

app.listen(PORT, () => {
  console.log(`Mock server is running on http://localhost:${PORT}`)
})

scriptsの追加

Next.jsのlocalサーバーと同時に、Expressサーバーも立ち上げようにします

package.json
"scripts": {
  "dev:mock": "tsx 'src/mocks/expressServer.ts'",
  "dev:web": "next dev",
  "dev": "pnpm dev:mock &pnpm dev:web",
}

動作確認

localhost:9999 でhandlerのエンドポイントに紐づくレスポンスを確認します

Server Componentsのfetchでデータが取得できることを確認します

src/app/test/page.tsx
const Page = async () => {
  const res = await fetch('http://localhost:9999/handler1')
  const data = await res.json()

  return (
    <pre>{JSON.stringify(data, null, 2)}</pre>
  )
}
export default Page

感想

mswは通常の使い方だと、リクエストの向き先を変えずに疎通できるメリットはありますが、設定が少し複雑でファイル数もそれに応じて増やす必要があります
特に、Next.jsのサーバーコンポーネントとの疎通は公式ドキュメントに書いておらず、詰まった方は多いのでは無いでしょうか
今後も新たな概念や、バージョンの違いでmswとの疎通の設定を修正するのであれば、今回のようにmswを別のPORTでAPIサーバーを立てる方がシンプルで簡単だと思いました

終わり!

Discussion