Tips & Tricks

Claude Code के साथ MSW API

Claude Code का उपयोग करके msw api सीखें। Practical tips और code examples शामिल हैं।

MSWでリアルなAPIモック環境 buildする

MSW(Mock Service Worker)はService Workerを利用してnetworkレベルでAPIrequestをインターセプトするモックlibrary है।testとブラウザdevelopmentの両方でsameモックhandlerを共有でき、実際のHTTPrequestとsame振る舞いを再現し है।Claude Codeはhandlerの設計 से型safeなモックbuild तक的確にサポートし है।

basic handler設計

Claude Codeにhandlerの構成を依頼 करें।

> MSWでuserAPIのモックhandlerを設計して。
> CRUD操作、error handling、response遅延を含めて。
import { http, HttpResponse, delay } from "msw";

// インメモリdatabase
let users: User[] = [
  { id: "1", name: "Alice", email: "[email protected]", role: "admin" },
  { id: "2", name: "Bob", email: "[email protected]", role: "editor" },
];

export const userHandlers = [
  // listfetch
  http.get("/api/users", async ({ request }) => {
    await delay(100);
    const url = new URL(request.url);
    const page = Number(url.searchParams.get("page") || "1");
    const perPage = Number(url.searchParams.get("perPage") || "20");
    const search = url.searchParams.get("search") || "";

    let filtered = users;
    if (search) {
      filtered = users.filter(
        (u) =>
          u.name.toLowerCase().includes(search.toLowerCase()) ||
          u.email.toLowerCase().includes(search.toLowerCase())
      );
    }

    const start = (page - 1) * perPage;
    const paginated = filtered.slice(start, start + perPage);

    return HttpResponse.json({
      data: paginated,
      meta: { total: filtered.length, page, perPage },
    });
  }),

  // 詳細fetch
  http.get("/api/users/:id", async ({ params }) => {
    await delay(50);
    const user = users.find((u) => u.id === params.id);
    if (!user) {
      return HttpResponse.json(
        { error: "userが見つかりません" },
        { status: 404 }
      );
    }
    return HttpResponse.json({ data: user });
  }),

  // create
  http.post("/api/users", async ({ request }) => {
    await delay(200);
    const body = (await request.json()) as Omit<User, "id">;
    const newUser: User = { ...body, id: String(Date.now()) };
    users.push(newUser);
    return HttpResponse.json({ data: newUser }, { status: 201 });
  }),

  // update
  http.put("/api/users/:id", async ({ params, request }) => {
    await delay(150);
    const body = (await request.json()) as Partial<User>;
    const index = users.findIndex((u) => u.id === params.id);
    if (index === -1) {
      return HttpResponse.json(
        { error: "userが見つかりません" },
        { status: 404 }
      );
    }
    users[index] = { ...users[index], ...body };
    return HttpResponse.json({ data: users[index] });
  }),

  // delete
  http.delete("/api/users/:id", async ({ params }) => {
    await delay(100);
    users = users.filter((u) => u.id !== params.id);
    return new HttpResponse(null, { status: 204 });
  }),
];

testでのintegration

Vitestとのintegrationpattern है।

import { setupServer } from "msw/node";
import { userHandlers } from "./handlers/user";

// test用server
const server = setupServer(...userHandlers);

beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

describe("UserList component", () => {
  it("userlist displayする", async () => {
    render(<UserList />);

    await waitFor(() => {
      expect(screen.getByText("Alice")).toBeInTheDocument();
      expect(screen.getByText("Bob")).toBeInTheDocument();
    });
  });

  it("APIerror時にerrormessage displayする", async () => {
    // test単位でhandlerをऊपर書き
    server.use(
      http.get("/api/users", () => {
        return HttpResponse.json(
          { error: "servererror" },
          { status: 500 }
        );
      })
    );

    render(<UserList />);

    await waitFor(() => {
      expect(screen.getByText("dataのfetchに失敗しました")).toBeInTheDocument();
    });
  });

  it("networkerror時にリトライbuttonがdisplayされる", async () => {
    server.use(
      http.get("/api/users", () => {
        return HttpResponse.error();
      })
    );

    render(<UserList />);

    await waitFor(() => {
      expect(screen.getByRole("button", { name: "再試行" })).toBeInTheDocument();
    });
  });
});

ブラウザでのdevelopment用モック

ブラウザ環境でService Worker के रूप में動作させるpattern है।

// src/mocks/browser.ts
import { setupWorker } from "msw/browser";
import { userHandlers } from "./handlers/user";
import { authHandlers } from "./handlers/auth";

export const worker = setupWorker(...userHandlers, ...authHandlers);

// src/main.tsx
async function enableMocking() {
  if (import.meta.env.DEV) {
    const { worker } = await import("./mocks/browser");
    return worker.start({
      onUnhandledRequest: "bypass",
    });
  }
}

enableMocking().then(() => {
  ReactDOM.createRoot(document.getElementById("root")!).render(
    <React.StrictMode>
      <App />
    </React.StrictMode>
  );
});

型safeなhandler設計

TypeScriptの型とMSWhandlerをintegrationするpattern है।

import { http, HttpResponse } from "msw";

// APItype definitions
interface ApiEndpoints {
  "GET /api/users": {
    response: { data: User[]; meta: PaginationMeta };
    params: never;
  };
  "GET /api/users/:id": {
    response: { data: User };
    params: { id: string };
  };
  "POST /api/users": {
    response: { data: User };
    body: CreateUserInput;
    params: never;
  };
}

// factoryーfunction
function createUserFactory(overrides: Partial<User> = {}): User {
  return {
    id: String(Math.random()).slice(2, 10),
    name: `User ${Math.random().toString(36).slice(2, 6)}`,
    email: `user-${Date.now()}@example.com`,
    role: "viewer",
    ...overrides,
  };
}

// testシナリオ用のhandlerセット
export const emptyStateHandlers = [
  http.get("/api/users", () =>
    HttpResponse.json({ data: [], meta: { total: 0, page: 1, perPage: 20 } })
  ),
];

export const errorHandlers = [
  http.get("/api/users", () =>
    HttpResponse.json({ error: "Internal Server Error" }, { status: 500 })
  ),
];

export const slowResponseHandlers = [
  http.get("/api/users", async () => {
    await delay(5000);
    return HttpResponse.json({ data: [createUserFactory()], meta: { total: 1, page: 1, perPage: 20 } });
  }),
];

Summary

MSWはnetworkレベルのモック से、実際のAPI通信に近い環境でtestとdevelopmentができ है।Claude Code का लाभ उठाकर、handler設計、testintegration、型safeな構成をकम समय मेंbuildpossible है।

ユニットtestとのintegrationはVitestऊपर級テクニックを、E2EtestでのutilizationはPlaywright E2Etest実践ガイドをदेखें。MSWofficial documentationもconfirmしておきましょう。

#Claude Code #MSW #APIモック #testing #frontend
मुफ़्त

मुफ़्त PDF: 5 मिनट में Claude Code चीटशीट

बस अपना ईमेल दर्ज करें और हम तुरंत A4 एक-पृष्ठ चीटशीट PDF भेज देंगे।

हम आपकी व्यक्तिगत जानकारी की सुरक्षा करते हैं और स्पैम नहीं भेजते।

Masa

लेखक के बारे में

Masa

Claude Code का गहराई से उपयोग करने वाले इंजीनियर। claudecode-lab.com चलाते हैं, जो 10 भाषाओं में 2,000 से अधिक पेजों वाला टेक मीडिया है।