かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

Vite React + MSW モックサーバーへのリクエストが `net::ERR_FAILED` になる件

Vite で作成した React (TypeScript) のプロジェクトで MSW (Mock Service Worker) を使って開発環境で API へのリクエストにモックを返すようにしたいと思っていたのですが React からのリクエストがことごとく net::ERR_FAILED [MSW] Failed to mock a "POST" request になってしましました。

問題を切り分ける

I think it's the error message that's confusing.

 return event.respondWith(
   handleRequest(event, requestId).catch((error) => {
     console.error(
       '[MSW] Failed to mock a "%s" request to "%s": %s',
       request.method,
       request.url,
       error,
     )
   }),
 )
While this wording makes sense in the context when there's an error during the mocked response, it's misleading when the error occurs during the original (bypassed) response.
cf. Unhandled request throw error: [MSW] Failed to mock a "POST" request to · Issue #841 · mswjs/msw · GitHub

今回 GraphQL で MWS を使っていたのですが、MSW は 該当するハンドラーがなかった場合も net::ERR_FAILED を返すようだったので、確実にハンドラがあることが分かる REST でエンドポイントを作成して GraphQL の呼び出しに問題があったのか、呼び出し以外に問題があるのかを切り分けます。

サンプルにあるようなシンプルな構成に変更する

問題が複雑なときは極力シンプルにせよ。古のインターネッツ(フォーラム)で教わった教えです。

src/mock/worker.ts

import { rest, setupWorker } from 'msw'

export const worker = setupWorker([
  rest.get('/test', (req, res, ctx) => {
    return res(
      ctx.json({ success: true }),
    );
  });
]);

呼び出す側も極力シンプルにします
src/App.tsx

import { useQuery } from 'react-query';

const fetcher = async () => {
  return await fetch(`${API_URL}/test`, {
    method: 'GET',
     headers: {
      'content-type': 'application/json;charset=UTF-8',
    },
  })
    .then((res) => {
      console.log('success fetch', res);
      return res.json();
    });
}

export const App: FC = () => {
  const { data, error } = useQuery('test', fetcher);
};

${API_URL}/test に GET リクエストを送ればどちらに問題があったかが判断できます。

  1. {'success': true} が返ってきたら GraphQL の呼び出し方に間違いがあった
  2. リクエストが net::ERR_FAILED なら MWS へのリクエストそのものに何かしらの問題がある

結果としては ${API_URL}/test への GET メソッドも net::ERR_FAILED になっていたので、リクエストの際に問題が発生している事が原因でした。

Vite の設定で CORS の問題を修正する

net::ERR_FAILED のエラーは CORS の問題の際にも表示されます。
今回は Vite で起動している dev server の localhost:3000API_URL のクロスオリジンの問題でブラウザが CORS のエラー返していることが原因でした。

cf. React SPA docker 上の API にアクセスで CORS が出た!! にハマる - かもメモ

CORS を許可する設定を追加する

server.cors
Type: boolean | CorsOptions
Configure CORS for the dev server. This is enabled by default and allows any origin. Pass an options object to fine tune the behavior or false to disable.
cf. Configuring Vite | Vite

Production の CORS の設定はサーバーサイドで行われている想定なので開発用 dev server では明示的にこのオプションを true にしておけば localhost での CORS の問題が解消されそうです。

vite.config.ts に次のオプションを追加

export default defineConfig({
  server: {
    open: true,
+   cors: false,
  },
  plugins: [react()],
});

これで再度サーバーを起動して ${API_URL}/test に GET メソッドを投げたら無事レスポンスを受けることができました!
これで開発環境で MSW を扱えるようになりました!!

今回は慣れてない GraphQL の呼び出しが原因なのかどうかの部分でハマってしまいました。
はやり問題をシンプルにして切り分けるのが大事。急がば回れ!を体感したのでした。

₍ ᐢ. ̫ .ᐢ ₎ おわり


[参考]

ハマったら問題を切り分けような…