Tips & Tricks

MSW API dengan Claude Code

Pelajari tentang msw api menggunakan Claude Code. Dilengkapi tips praktis dan contoh kode.

MSWでリアルなAPImock環境をpembangunan

MSW(Mock Service Worker) Service Worker pemanfaatan ネットワークレベル APIrequest インターセプト mocklibrary.test dan browserpengembangan 両方 同じmockhandler berbagi き、実際 HTTPrequest dan 同じ振る舞い 再現.Claude Code handler 設計 dari type safetyなmockpembangunanま 的確 サポート.

dasar的なhandler設計

Claude Code handler 構成 依頼し.

> MSW dengan penggunaAPI mockhandler 設計して。
> CRUDoperasi、errorハンドリング、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 = [
  // daftarpengambilan
  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 },
    });
  }),

  // 詳細pengambilan
  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: "pengguna 見つかりません" },
        { status: 404 }
      );
    }
    return HttpResponse.json({ data: user });
  }),

  // pembuatan
  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 });
  }),

  // pembaruan
  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: "pengguna 見つかりません" },
        { status: 404 }
      );
    }
    users[index] = { ...users[index], ...body };
    return HttpResponse.json({ data: users[index] });
  }),

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

integrasi test

Vitest dan integrasipola.

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 komponen", () => {
  it("penggunadaftar tampilan", async () => {
    render(<UserList />);

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

  it("APIerror時 errorpesan tampilan", async () => {
    // test単位 handler 上書き
    server.use(
      http.get("/api/users", () => {
        return HttpResponse.json(
          { error: "servererror" },
          { status: 500 }
        );
      })
    );

    render(<UserList />);

    await waitFor(() => {
      expect(screen.getByText("データ pengambilan gagalしま")).toBeInTheDocument();
    });
  });

  it("ネットワークerror時 リトライtombol tampilanされる", async () => {
    server.use(
      http.get("/api/users", () => {
        return HttpResponse.error();
      })
    );

    render(<UserList />);

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

pengembangan用mock browser

browser環境 Service Worker sebagai 動作させるpola.

// 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>
  );
});

type safetyなhandler設計

TypeScript 型 dan MSWhandler integrasi pola.

import { http, HttpResponse } from "msw";

// API型definisi
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;
  };
}

// ファクトリーfungsi
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 ネットワークレベル mock より、実際 API通信 近い環境 test dan pengembangan bisa dilakukan.Claude Code pemanfaatanすれば、handler設計、testintegrasi、type safetyな構成 waktu singkat pembangunandimungkinkan.

ユニットtest dan integrasi Vitest上級テクニック 、E2Etest pemanfaatan Playwright E2Etest実践panduan silakan lihat.MSW公式dokumen juga konfirmasi おき.

#Claude Code #MSW #APImock #testing #frontend