frontend-wire

star 0

阶段 5a。把前端从 mock 切到真后端 API。验证字段、状态、错误处理一致。当用户说"接真接口"、"切真 API"、"前端联调"时触发。前置:对应业务契约 status=implemented(后端已实现)。

lifecoder1988 By lifecoder1988 schedule Updated 5/21/2026

name: frontend-wire description: 阶段 5a。把前端从 mock 切到真后端 API。验证字段、状态、错误处理一致。当用户说"接真接口"、"切真 API"、"前端联调"时触发。前置:对应业务契约 status=implemented(后端已实现)。

阶段 5a:前端切真 API

前置检查

ls docs/api-contracts/*.yaml

读 status。只能处理 status: implemented 的契约。如果还是 confirmed → 后端未实现 → 拒绝:

❌ 无法切真接口。

原因:以下契约后端还未实现,只是 confirmed:
- updateTask.yaml
- listTasks.yaml

请先 api-implement skill 实现后端,再回来切真接口。

工作流程

1. 检查现状

# 现有 mock handlers
ls frontend/src/mocks/handlers/

# 现有 API client
ls frontend/src/api/

# 当前模式
grep VITE_MODE frontend/.env*

2. 确认后端可达

# 假设后端跑在 :8000
curl -s http://localhost:8000/api/v1/health || echo "后端没起,请 make backend-dev"

如果后端没起,提示用户启动后再继续。

3. 配置真 API base URL

frontend/.env.development:

VITE_API_BASE_URL=http://localhost:8000/api/v1

4. 切换模式

入口文件改成:

async function enableMocking() {
  if (import.meta.env.VITE_USE_MOCK !== 'true') return
  const { worker } = await import('./mocks/browser')
  await worker.start({ onUnhandledRequest: 'bypass' })
}

新增 frontend/.env.mock:

VITE_USE_MOCK=true

package.json scripts:

{
  "dev": "vite",
  "dev:mock": "vite --mode mock"
}

5. 逐个验证页面

逐个(这一步不批量),按场景:

  1. 启动后端 + 前端 npm run dev
  2. 打开页面 → F12 Network
  3. 验证清单:
    • ✅ 请求 URL 正确(指向真后端,不是 MSW)
    • ✅ 请求带 Authorization header
    • ✅ 响应字段与前端 type 完全匹配
    • ✅ 错误响应触发正确的 UI 状态
    • ✅ Loading / Empty / Error 三态都正常

6. 处理发现的问题

6.1 字段对不上(但 mock 阶段没发现)

最常见的情况:mock 数据偷懒,没填 nullable 字段,真 API 返回 null,UI 崩。

修法:改 UI 处理 null,不改 API。

// 改前
<div>{task.assignee.name}</div>

// 改后
<div>{task.assignee?.name ?? '未指派'}</div>

6.2 真 API 行为与 mock 不一致

例:mock 删除直接 200,真 API 返回 204。

修法:对照 OpenAPI 检查谁对。OpenAPI 是事实源。

  • mock 错 → 改 mock(顺手)
  • UI 假设错 → 改 UI

6.3 真 API 与 OpenAPI 不一致

严重问题。这说明后端实现偏离了契约。

立即停下报告:

⚠️ 后端实现偏离 OpenAPI:

GET /api/v1/tasks/{id} 实际返回:
{ "id": "...", "title": "...", "owner": "..." }    ← owner 字段

OpenAPI 定义:
{ "id": "...", "title": "...", "created_by": "..." }   ← created_by

需要决定:
A. 后端改回 created_by(符合 OpenAPI)
B. 改 OpenAPI 为 owner(并通知前端 mock 重新对齐)

请决定。如选 A,需要 api-implement 修补;选 B,需要 api-design 修订后重跑 mock-align。

7. 改造 fetch 调用

如果之前 mock 阶段用了硬编码 fetch,统一改为生成的 client:

// 改前
const res = await fetch('/api/v1/tasks/' + id)
const task = await res.json()

// 改后(如果用了 orval/react-query)
const { data: task } = useGetTask({ id })

错误处理统一(src/api/client.ts 拦截器):

client.interceptors.response.use(
  (res) => res,
  (err) => {
    if (err.response?.status === 401) {
      // token 失效,跳登录
    }
    // 抛出统一的 APIError
    throw new APIError(err.response?.data?.error)
  }
)

8. 验证清单

每个页面跑一遍:

  • 正常加载数据
  • 创建 / 更新 / 删除 操作成功
  • 错误响应 UI 友好(显示 error.message 或 i18n)
  • Loading 骨架屏正常
  • Empty 状态有 CTA
  • 鉴权失败跳登录
  • 类型检查 tsc --noEmit 通过
  • 浏览器 Console 0 错误

9. 输出切换总结

## 前端切真 API 总结

### 模式
- `npm run dev` → 真 API
- `npm run dev:mock` → MSW mock(保留)

### 改造文件
- frontend/.env.development
- frontend/.env.mock
- frontend/src/main.tsx(条件加载 MSW)
- frontend/src/api/client.ts(拦截器、错误处理)
- frontend/src/pages/* (各页面 fetch → react-query)

### 已验证页面
- ✅ /login        登录正常,401 提示
- ✅ /projects     列表加载,空状态正确
- ✅ /projects/:id/board  看板拖拽未实现(留作下个迭代)
- ✅ /tasks/:id    详情正常,删除→列表移除

### 发现的问题

✅ 已修复:
- TaskCard 没处理 assignee 为 null → 加默认值
- 错误响应没 trace_id 展示 → 加到 Toast

⚠️ 待决策:
- 无

### Verify
- tsc --noEmit: ✅
- vitest: ✅
- 浏览器手测: ✅ 4 个页面 0 错误

### 下一步
- 调用 e2e-test skill 写端到端测试

严禁

  1. ❌ 在后端未 implemented 时开工
  2. ❌ 删除 mock handlers(保留,用于 dev:mock 和测试)
  3. ❌ 修改 OpenAPI(发现真 API 偏离 → 停下报告)
  4. ❌ 修改 frontend/src/api/types.ts(机器生成)
  5. ❌ 在切换中"顺手"美化 UI
  6. ❌ 隐藏字段不匹配
Install via CLI
npx skills add https://github.com/lifecoder1988/ai-bbs --skill frontend-wire
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator
lifecoder1988
lifecoder1988 Explore all skills →