🎭
MSWで型安全にConnectの通信をモックする
結論
MSWを使用してConnectの通信をモックする場合、以下のようなヘルパー関数を用意することで型安全かつ簡潔にモックを記述できます:
import { ServiceType, MessageType } from "@bufbuild/protobuf";
import { RequestHandler, rest } from "msw";
export const mockConnectWeb =
<T extends ServiceType>(service: T) =>
<U extends keyof T["methods"]>(props: {
method: U;
data: T["methods"][U]["O"] extends MessageType<infer O> ? O : never;
}): RequestHandler => {
return rest.all(
"*/" + service.typeName + "/" + service["methods"][props.method]?.name,
(_req, res, ctx) => {
return res(ctx.status(200), ctx.json(props.data));
}
);
};
詳細な実装と使い方
モックヘルパー関数の特徴
このヘルパー関数には以下の特徴があります:
- 型安全性
- ServiceTypeとそのメソッドの型を保証
- レスポンスデータの型チェックを実現
- 使いやすさ
- リクエストパスを自動的に構築
- MSWのHandlerを適切に生成
実践的な使用例
Storybookなどでの使用例を見てみましょう:
export const Default: Story = {
render: () => <EventManagerComponent />,
parameters: {
msw: {
handlers: [
mockConnectWeb(EventManagementService)({
method: "getEventDetails",
data: new EventDetailsResponse(),
}),
mockConnectWeb(EventManagementService)({
method: "saveEventData",
data: new SaveEventResponse(),
}),
// 他のエンドポイントのモック...
],
},
},
};
利点と注意点
利点
- 型の恩恵
- 存在しないメソッド名の指定を防止
- レスポンスの型不一致を防止
- IDEの補完が効く
- 保守性
- モック実装がシンプル
- 再利用が容易
- APIの変更が型システムで追跡可能
注意点
- エラーケースの考慮
- 現状は200レスポンスのみ対応
- エラーレスポンスが必要な場合は拡張が必要
- 実装の制限
- 単純なレスポンス返却のみ対応
- 複雑なモックが必要な場合は個別対応が必要
発展的な使い方
エラーケース対応
エラーケースにも対応したい場合は、以下のように拡張できます:
export const mockConnectWebWithError =
<T extends ServiceType>(service: T) =>
<U extends keyof T["methods"]>(props: {
method: U;
error?: { status: number; message: string };
data?: T["methods"][U]["O"] extends MessageType<infer O> ? O : never;
}): RequestHandler => {
return rest.all(
"*/" + service.typeName + "/" + service["methods"][props.method]?.name,
(_req, res, ctx) => {
if (props.error) {
return res(
ctx.status(props.error.status),
ctx.json({ message: props.error.message })
);
}
return res(ctx.status(200), ctx.json(props.data));
}
);
};
おわりに
MSWとConnectを組み合わせることで、型安全かつメンテナンス性の高いAPIモックを実現できます。特にStorybookでのUI開発において有用です。必要に応じてエラーケースの対応など、機能を拡張していくことで、より実践的な使用が可能になります。
Discussion