👋

Nuxt3とMSWの相性が悪いのでjson-serverで代替する

2024/01/03に公開

環境情報

  • Nuxt3.8.2(SSR)
  • Vue3.3.11
  • Node.js20.9.0
  • json-server0.17
  • Laravel10(外部API)

背景と前提情報

Nuxt3でAPIモックを導入したいと思い、ReactやNextで使用していたMSW(MockServiceWorker)をインストールしようとしたところかなり相性がよくないことがわかりました。

なぜ相性が良くないのか

  • Nuxt3でHTTPリクエストする際にuseFetch、useAsyncData、$fetchが推奨されている
  • MSWが$fetchに対応されていない

参考記事:https://zenn.dev/harusame0616/articles/d497a84a6cb792

一応上記記事ではnodeの--no-experimental-fetchオプションを使用することで導入も可能なようでしたが、今回のプロジェクトではNuxtサーバーからLaravelの外部APIを実行する想定で、その外部APIのみをモックしたかったこともあり断念しました。

今回の構成

上述でも少し触れましたが、NuxtサーバーAPIを経由してLaravelで実装したAPIを実行する構成となっています。今回はLaravel APIの部分のみをモック化していきます。

代替としてjson-severを導入

json-serverをインストールするコマンドを実行します。

npm install --save-dev json-server

mock用データの作成

Nuxtプロジェクト直下にmocksディレクトリを作成し、その配下にdb.jsonとroutes.jsonを作成します。
db.jsonには返却したいレスポンスの固定値を記述します。

db.json
{
    "user1": {
        "data": {
            "last_name": "山田",
            "first_name": "太郎",
            "last_name_kana": "ヤマダ",
            "first_name_kana": "タロウ"       
        }
    },
    "user2": {
        "data": {
            "last_name": "山田",
            "first_name": "花太郎",
            "last_name_kana": "ヤマダ",
            "first_name_kana": "ハナタロウ"
        }
    }
}

routes.jsonにはAPIエンドポイントのマッピングを記述できます。
json-serverは複数階層のルーティング(/api/userなど)を設定できないため、routes.jsonにエンドポイントの変更を記述することで対応する必要があります。

routes.json
{
    "/api/user/1": "/user1",
    "/api/user/2": "/user2"
}

json-serverの起動

json-serverを起動するコマンドを実行します。オプションに

$ json-server --watch db.json --routes routes.json

  \{^_^}/ hi!

  Loading mocks/db.json
  Loading mocks/routes.json
  Done

  Resources
  http://localhost:3000/user1
  http://localhost:3000/user2

  Other routes
  /api/user/1 -> /user1
  /api/user/2 -> /user2

  Home
  http://localhost:3000

curlコマンドで実際にレスポンスを取得できるか試してみます。

$ curl -X GET 'http://localhost:3000/api/user/1'
{
  "data": {
    "last_name": "山田",
    "first_name": "太郎",
    "last_name_kana": "ヤマダ",
    "first_name_kana": "タロウ"
}

$ curl -X GET 'http://localhost:3000/api/user/2'
{
  "data": {
    "last_name": "山田",
    "first_name": "花太郎",
    "last_name_kana": "ヤマダ",
    "first_name_kana": "ハナタロウ"
}

ルーティングのマッピングも正常に動作していることを確認できました。

Nuxtの設定修正

json-serverを参照するかLaravel APIを参照するかの切り替えを簡単にできるように設定を追加しておきます。

.envの修正

ここではLaravel APIのエンドポイントを指定しておきます。
(今回は例としてhttp://localhost:8080)

.env
NUXT_API_URL=http://localhost:8080

nuxt.config.tsの修正

runtimeConfigの設定を追加します。その他の設定は今回は割愛してます。

nuxt.config.ts
export default {
    runtimeConfig: {
        api: { url: '' }
    }
}

package.jsonの修正

scriptsにjson-server起動コマンドを追加します。

package.json
{
  "scripts": {
    "build": "nuxt build",
    "dev": "nuxt dev --inspect",
+   "dev-mock": "NUXT_API_URL=http://localhost:3000 nuxt dev --inspect & json-server --watch mocks/db.json --routes mocks/routes.json",
    // ~~ 以下省略 ~~
  }
}

これでnpm run dev-mockを実行するとjson-serverとNuxtのビルドサーバーを同時に起動できるようになりました。
コマンド実行の際にNUXT_API_URL=http://localhost:3000で環境変数の上書きをしているため、useRuntimeConfig().api.urlでソース側の修正はせずに向け先の変更が可能となります。
Laravel APIを参照したい場合はこれまで通りnpm run devでOKです。

MSWと比較してのデメリット

  • json-server用のプロセスを立てる必要があること
  • ルーティングの階層をネストするにはroutes.jsonを使わないといけないところ
  • postメソッドを使った場合、db.jsonが書き換わるところ

まとめ

Nuxt API側のみaxios等でリクエストしてMSWを採用することも検討しましたが、componentとAPIで別のリクエスト手段を使用するのも抵抗があったので今回はMSWの採用を見送る方針としました。
また、時間があまりなかったのでMSWを上手く導入する方法を深く追及しませんでしたが、MSWがNuxt3の$fetchに対応すれば切り替えを検討したいと思ってます。

Discussion