MSW API with Claude Code
Learn about msw api using Claude Code. Practical tips and code examples included.
MSWでリアルなAPIモック環境を構築する
MSW(Mock Service Worker)はService Workerを利用してネットワークレベルでAPIリクエストをインターセプトするモックライブラリです。テストとブラウザ開発の両方で同じモックハンドラーを共有でき、実際のHTTPリクエストと同じ振る舞いを再現します。Claude Codeはハンドラーの設計から型安全なモック構築まで的確にサポートします。
基本的なハンドラー設計
Claude Codeにハンドラーの構成を依頼しましょう。
> MSWでユーザーAPIのモックハンドラーを設計して。
> CRUD操作、エラーハンドリング、レスポンス遅延を含めて。
import { http, HttpResponse, delay } from "msw";
// インメモリデータベース
let users: User[] = [
{ id: "1", name: "Alice", email: "[email protected]", role: "admin" },
{ id: "2", name: "Bob", email: "[email protected]", role: "editor" },
];
export const userHandlers = [
// 一覧取得
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 },
});
}),
// 詳細取得
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: "ユーザーが見つかりません" },
{ status: 404 }
);
}
return HttpResponse.json({ data: user });
}),
// 作成
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 });
}),
// 更新
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: "ユーザーが見つかりません" },
{ status: 404 }
);
}
users[index] = { ...users[index], ...body };
return HttpResponse.json({ data: users[index] });
}),
// 削除
http.delete("/api/users/:id", async ({ params }) => {
await delay(100);
users = users.filter((u) => u.id !== params.id);
return new HttpResponse(null, { status: 204 });
}),
];
テストでの統合
Vitestとの統合パターンです。
import { setupServer } from "msw/node";
import { userHandlers } from "./handlers/user";
// テスト用サーバー
const server = setupServer(...userHandlers);
beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
describe("UserList コンポーネント", () => {
it("ユーザー一覧を表示する", async () => {
render(<UserList />);
await waitFor(() => {
expect(screen.getByText("Alice")).toBeInTheDocument();
expect(screen.getByText("Bob")).toBeInTheDocument();
});
});
it("APIエラー時にエラーメッセージを表示する", async () => {
// テスト単位でハンドラーを上書き
server.use(
http.get("/api/users", () => {
return HttpResponse.json(
{ error: "サーバーエラー" },
{ status: 500 }
);
})
);
render(<UserList />);
await waitFor(() => {
expect(screen.getByText("データの取得に失敗しました")).toBeInTheDocument();
});
});
it("ネットワークエラー時にリトライボタンが表示される", async () => {
server.use(
http.get("/api/users", () => {
return HttpResponse.error();
})
);
render(<UserList />);
await waitFor(() => {
expect(screen.getByRole("button", { name: "再試行" })).toBeInTheDocument();
});
});
});
ブラウザでの開発用モック
ブラウザ環境でService Workerとして動作させるパターンです。
// 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>
);
});
型安全なハンドラー設計
TypeScriptの型とMSWハンドラーを統合するパターンです。
import { http, HttpResponse } from "msw";
// API型定義
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;
};
}
// ファクトリー関数
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,
};
}
// テストシナリオ用のハンドラーセット
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はネットワークレベルのモックにより、実際のAPI通信に近い環境でテストと開発ができます。Claude Codeを活用すれば、ハンドラー設計、テスト統合、型安全な構成を短時間で構築可能です。
ユニットテストとの連携はVitest上級テクニックを、E2Eテストでの活用はPlaywright E2Eテスト実践ガイドを参照してください。MSW公式ドキュメントも確認しておきましょう。
Free PDF: Claude Code Cheatsheet in 5 Minutes
Just enter your email and we'll send you the single-page A4 cheatsheet right away.
We handle your data with care and never send spam.
Level up your Claude Code workflow
50 battle-tested prompt templates you can copy-paste into Claude Code right now.
About the Author
Masa
Engineer obsessed with Claude Code. Runs claudecode-lab.com, a 10-language tech media with 2,000+ pages.
Related Posts
7 CLAUDE.md Templates for Claude Code You Can Copy Into Real Projects
Copy-paste 7 practical CLAUDE.md templates for solo apps, content sites, APIs, teams, and legacy codebases, plus the failure cases to avoid.
Claude Code Approval and Sandbox Guide | Safe Daily Settings for Real Work
Learn how to split Claude Code actions into allow, ask, deny, and sandboxed workflows with working settings, hooks, and rollout examples.
Complete Beginner's Guide to Claude Code 2026 | 7 Steps from Zero to Production-Ready
A complete beginner's guide for first-time Claude Code users. From installation to integrating it into your real development workflow — covering every pitfall Masa ran into when starting out.
Related Products
50 Battle-Tested Claude Code Prompt Templates
Copy, paste, ship. 50 production-ready prompts.
Use proven prompts for code review, refactoring, testing, documentation, debugging, architecture, and incident response.
The Complete Claude Code Setup & Configuration Guide
From install to team-ready workflow.
A practical guide to installation, CLAUDE.md, hooks, MCP servers, permissions, IDE setup, and CI/CD workflows.