MSW 在前端项目中的正确打开方式:从“造数据”到“定义接口”
为什么要重新理解 MSW
在很多项目里,MSW 被当成了:
- 一个 mock 数据工具
- 一个本地调试的临时方案
- 一个替代 mock.js 的库
但在实际工程中,如果这样使用 MSW,价值会非常有限,甚至会制造新的混乱。
我们最终达成的共识是:
MSW 不是用来“造假数据”的,而是用来“定义接口行为”的。
MSW 的合理定位
在我们的体系中:
- MSW ≠ mock 数据生成器
- MSW ≠ 测试专用工具
- MSW = 可执行的接口契约
它承担的职责只有三件事:
- 明确 URL 与 HTTP Method
- 明确请求与响应结构
- 明确错误码与异常场景
一个最小但正确的 MSW handler
1 | import { http, HttpResponse } from 'msw' |
注意几点:
- 永远返回完整 ApiResponse
- 错误分支和成功分支都要写
- 不关心真实数据库,只关心协议
MSW 目录结构设计
一个可维护的 MSW 目录应该是按接口域拆分,而不是按页面拆分:
1 | src/mocks/ |
handlers
- 描述接口行为
- 不直接写大量数据
- 只处理协议与分支逻辑
factories
- 负责生成结构正确的数据
- 可复用
- 不关心接口 URL
handlers 应该写什么,不该写什么
应该写
- 参数校验失败
- 鉴权失败
- 资源不存在
- 业务限制错误
不应该写
- 复杂随机逻辑
- 模拟数据库
- 页面专属分支
如果 handler 中出现大量 Math.random(),基本说明职责已经跑偏。
一个典型的 CRUD handler 写法
1 | export const userHandlers = [ |
MSW 与页面的关系
一个非常重要的原则:
页面不应该知道自己在使用 MSW。
这意味着:
- 请求方式与真实接口完全一致
- 错误处理逻辑完全一致
- try / catch 行为一致
MSW 的存在对页面是透明的。
如何新增一个接口(标准流程)
当页面需要一个新接口时:
- 在 MSW 中先定义 handler
- 明确请求参数与返回结构
- 明确错误码
- 页面基于该接口开发
- 将结构登记到 OpenAPI 文档
- 后端实现接口
禁止直接根据后端 Swagger 写页面。
MSW 与 OpenAPI 的关系
- MSW 是行为定义
- OpenAPI 是结构与文档定义
在实践中:
- MSW 是开发驱动
- OpenAPI 是交付物
- Swagger 是后端产出
常见误区
把 MSW 当成“前端数据库”
这会导致:
- handler 极度复杂
- 行为不可预测
- 后端无法对齐
handler 按页面拆分
接口属于领域,不属于页面。
什么时候不该用 MSW
- 单页 Demo
- 一次性活动页
- 已完全稳定、无演进空间的接口
MSW 适合持续演进的系统。
总结
MSW 的真正价值不在于“快”,而在于:
- 提前冻结接口语义
- 降低协作摩擦
- 提供可执行的接口契约
当你开始用 MSW 讨论接口结构,而不是写假数据时,它才真正发挥了价值。
MSW 在前端项目中的正确打开方式:从“造数据”到“定义接口”