Claude Code 自動維護 API docs:OpenAPI spec、TypeScript types、example response 同步
API 改完,docs 永遠落後幾個版本。教用 Claude Code 同步 OpenAPI spec、TypeScript types、example response 三層 docs,pre-commit hook 自動跑、PR review 必有 docs diff。
情境
你個 B2B API 上咗 prod 半年。Endpoint 由 12 條變 47 條。
文件呢?
/docs/api.md—— 最後一次更新喺 3 個月前openapi.yaml—— 6 個 endpoint 仲叫舊名- Frontend 嘅
api-types.ts—— 手動 copy 嘅、有兩個 field 同 backend 唔同 example-response.json—— 嗰隻 deprecateduser_idfield 仲喺度
結果:客戶 integration team 第三次寫 email 投訴「why does the response shape not match your docs?」。Frontend 同事每隔幾日就撞一次 type mismatch。
問題唔係冇人寫 docs,係docs 同 code 根本唔係同一個 source of truth。每次靠人手對齊,總有一層漏。
呢篇教用 Claude Code 建立 3-tier doc sync:
- OpenAPI spec —— single source of truth,由 route handler 直接生成
- TypeScript types —— spec 出 codegen,frontend / SDK 直接 import
- Example payload —— Claude 跑落 staging、核實個 response,再更新 example
加埋一個 pre-commit hook + /api-doc slash command —— 加新 endpoint,docs 自動跟。
跟住做
1. Route → OpenAPI spec 自動 sync
第一層 source of truth 係 openapi.yaml,但唔係手寫,係由 route file 推導出嚟。
假設你用 Hono / Express,route 大概係咁:
// src/routes/orders.ts
app.post('/api/orders', async (c) => {
const body = CreateOrderSchema.parse(await c.req.json())
const order = await createOrder(body)
return c.json({ success: true, data: order })
})
關鍵:Zod schema 已經喺度,OpenAPI 要嘅資訊就喺 schema 入面。
加個 CLAUDE.md rule 落 project root:
## OpenAPI Sync Rule
每次加 / 改 route handler,必須同步更新 openapi.yaml:
1. Route path + method 對應 paths section
2. Zod schema 用 zod-to-openapi 轉換做 requestBody / responseBody
3. 唔好手寫 schema —— 永遠由 Zod source 推
4. 如果 Zod schema 改咗 field,openapi.yaml 對應 section 必須同步
Claude Code 讀到呢條 rule,你下次叫佢加 endpoint 嘅時候,佢就會自動更新 spec。
裝 zod-to-openapi:
npm install @asteasolutions/zod-to-openapi
呢個 lib 等 Zod schema 直接吐出 OpenAPI fragment,Claude 唔使再重複寫多次 schema。
2. TypeScript types codegen
OpenAPI 有咗,frontend types 直接由佢生出嚟。
npm install -D openapi-typescript
加條 script 落 package.json:
{
"scripts": {
"gen:types": "openapi-typescript openapi.yaml -o src/types/api.ts"
}
}
跑:
pnpm gen:types
src/types/api.ts 入面會出晒所有 endpoint 嘅 request / response 型別:
export interface paths {
'/api/orders': {
post: {
requestBody: { content: { 'application/json': components['schemas']['CreateOrder'] } }
responses: { 200: { content: { 'application/json': components['schemas']['Order'] } } }
}
}
}
Frontend / SDK 直接 import:
import type { paths } from '@/types/api'
type CreateOrderBody = paths['/api/orders']['post']['requestBody']['content']['application/json']
人手 copy field 嘅日子玩完。 Spec 改一行,types 即刻跟。
3. Example payload test + 核實 pipeline
最後一層:example response。呢層最易過時,因為冇人想親手跑 endpoint 再 copy 個 JSON 出嚟。
寫條 script scripts/refresh-examples.ts:
import { spec } from '../openapi'
for (const endpoint of spec.paths) {
const response = await fetch(`https://staging.api.example.com${endpoint.path}`, {
method: endpoint.method,
headers: { Authorization: `Bearer ${process.env.STAGING_TOKEN}` },
body: endpoint.exampleRequest,
})
const data = await response.json()
await writeFile(`docs/examples/${endpoint.id}.json`, JSON.stringify(data, null, 2))
}
跑:
pnpm tsx scripts/refresh-examples.ts
跟住叫 Claude Code 核實:
讀 docs/examples/ 入面所有 JSON 同 openapi.yaml 嘅 response schema。對比每一個 example: 有冇缺 field(spec 講有、example 冇) 有冇多 field(example 有、spec 冇)—— 通常代表 spec 落後 Field type 有冇對唔上 逐個 endpoint 出 diff report,列明邊個要改邊一層。
Claude 會逐個檢、出一份 markdown report、指明「呢個 example 嘅 deprecated field 要移除」或者「spec 漏咗 created_at」。
呢個三層循環跑完一次,docs 同 code 就完全對齊。
4. /api-doc slash command 一句話加新 endpoint
最後加個 project-level slash command。喺 .claude/commands/api-doc.md:
---
description: 加新 API endpoint + 自動 sync 三層 docs
---
加新 endpoint 嘅 workflow:
1. 喺 src/routes/ 加 route handler(Zod schema 必寫)
2. Run pnpm openapi:emit —— openapi.yaml 自動更新
3. Run pnpm gen:types —— TypeScript types 自動 codegen
4. Run pnpm tsx scripts/refresh-examples.ts —— example payload 跑落 staging
5. Verify:對比 example vs spec,出 diff
6. Commit:openapi.yaml / types / examples 三層同 route handler 一齊入 PR
用家會用一句話 describe endpoint。你完成 1-6 步先返人。
之後 Claude Code 入面:
/api-doc 加一個 GET /api/orders/:id endpoint,攞返單筆訂單詳情,permission 同 POST 一樣
Claude 會跑晒成條鏈:route → schema → spec → types → example → 核實 → commit。
收工。
加埋一個 pre-commit hook(.husky/pre-commit):
#!/bin/sh
pnpm openapi:emit
pnpm gen:types
git diff --exit-code openapi.yaml src/types/api.ts || {
echo "❌ Docs out of sync. Commit auto-updated files."
exit 1
}
任何 PR 想入 main,docs 唔同步就直接擋住。
變化
變化 1:GraphQL schema 版(vs REST)
GraphQL 唔使用 OpenAPI —— schema.graphql 本身就係 source of truth。但同步 example query / response 嘅問題一樣存在。
Claude Code workflow:
讀 schema.graphql,對每個 Query / Mutation 生成:
1. Example query (with fragments)
2. 落 staging 跑、record response
3. 寫入 docs/graphql-examples/
加 codegen(@graphql-codegen/cli)出 TypeScript types,做法同 REST 版完全一樣。
變化 2:Python FastAPI 版(Pydantic 同 schema)
FastAPI 識自己吐 OpenAPI —— /openapi.json 即係 source of truth。
curl http://localhost:8000/openapi.json > openapi.json
之後成條鏈同 TypeScript 版一樣:openapi-typescript-codegen 出 client types,Claude 核實 example。
關鍵:Pydantic model 同 endpoint signature 已經夠表達,唔使再加多一層。Claude 直接讀 router file,spec 就跟住 import 入嚟嘅 Pydantic schema 同步。
變化 3:Webhook docs(asymmetric send/receive)
Webhook 同 REST 唔同 —— 係你 send 出去,但收嘅人要知你個 payload shape。
呢類 docs 要分兩面:
- outgoing —— 你發乜(payload schema + 例子)
- expected response —— 對方應該回乜(成功 / 重試)
用 AsyncAPI spec(即係 OpenAPI 嘅 event 版本)。Claude Code workflow:
讀 src/webhooks/ 嘅 publisher code,提取每個 event 嘅:
- Topic / event name
- Payload Zod schema
- Retry policy
出 asyncapi.yaml,跟住生 markdown docs 畀 partner team
Partner 接 webhook 嘅時候,永遠睇返自動同步嗰份 docs。
拆解:點解 work,同邊度會仆街
跟到上面就已經用得。下面呢段係畀想由「跑一次 sync OK」做到「成個 team 用足一年都信得過」嘅人——初學者可以跳過,唔影響你跟住做。
自動化 docs 最唔老實嘅地方係:第一次 generate 對晒,唔代表第三十次 commit 都對。呢條三層鏈,實際會喺呢幾個位仆街,你要預咗:
1. example refresh 跑落 staging 但攞錯或者攞唔到資料
refresh-examples.ts 假設每個 endpoint 都用同一個 token、同一份 example request 就 call 得通。實際上 POST 要 valid body、/api/orders/:id 要一個真係存在嘅 id、有啲 endpoint 仲要前置狀態(要先有張單先 GET 到)。
- 會出事:一係 400 或者 404,一係 staging 個 DB 啱啱清空,個 example 變咗空 array 或者 error body,然後當「正確 response」寫入 docs。客戶睇住份 docs 照做,先發現 shape 根本唔啱。
- 點救:每個 endpoint 喺 spec 入面擺定一個有效嘅 example request;寫 script 嗰陣 assert HTTP status 喺 2xx 先肯寫入,唔係就 fail 出聲。寧願 refresh 失敗,都唔好靜雞雞寫個錯 example 入去。
2. Claude 對比 example vs spec 嗰陣「眼瞓」漏咗 field
verify prompt 叫 Claude 逐個 endpoint 對 field。但 response 一深(nested object、array of object、data.items[].metadata)、endpoint 一多,LLM 唔係逐 byte diff,係靠理解,長 context 之下會靜靜漏報。
- 會出事:佢出份 report 話「全部對齊」,但其實有個 nested field 嘅 type 由 number 變咗 string,冇人察覺,直到 frontend run-time 先爆。
- 點救:結構性對比(spec response schema vs example JSON)交畀程式做——寫個細 validator 用 spec 去 validate example,真正逐 field 行。Claude 嘅角色擺喺「解釋點解唔 match、應該改邊一層」,唔好靠佢做 exact diff。
3. pre-commit hook 一慢,大家就 --no-verify 繞過
個 hook 每次 commit 都 openapi:emit 加 gen:types,project 一大,呢兩步可能要跑好幾秒。開發者趕住 commit,好快就學識 git commit --no-verify,個攔截形同虛設。
- 會出事:本地攔截被人繞過,docs 又開始漂移,你以為有自動化其實冇。
- 點救:pre-commit 只做快嘅嘢(format、lint),把 docs sync 嘅硬性把關擺去 CI(PR 入 main 嗰度)。CI 跑唔過就 merge 唔到,呢度繞唔到。本地 hook 係提醒,CI 先係真正防線。
4. emit 出嚟嘅 diff 順序唔穩,逼到次次都有 noise
zod-to-openapi 或者 codegen 工具如果唔保證 output 嘅 key 順序穩定(或者你升咗版),同一份 source 生出嚟嘅 yaml 可能行序唔同。pre-commit 嗰句 git diff --exit-code 就會次次都話「out of sync」,就算你乜都冇改。
- 會出事:每次 commit 都被 hook 擋,大家煩到索性關咗佢,前功盡廢。
- 點救:generate 之後過一層 deterministic format(固定 key 排序、固定 indent),例如統一用
prettier寫返個 yaml。確保同一 source 出 byte-identical output,個 diff 先有意義。
5. 改 Zod schema 改壞咗,等於一鍵把錯誤推落三層
呢套嘢嘅威力係 single source 一改、三層全跟。但反過嚟講——你改 Zod schema 改錯咗(打多隻字、type 寫錯),個錯就會自動 codegen 落 types、寫入 example、出晒去 partner docs,一路冇人 review。
- 會出事:source 錯,downstream 全錯,而且因為係「自動」,反而冇人逐層望,錯得仲齊。
- 點救:source 層(route handler 入面嘅 Zod schema)嘅改動,要當正常 code 咁認真 review;加埋對住舊 spec 嘅 contract test——field 由 required 變 optional、type 變更呢類 breaking change,要 CI 出聲示警,唔好靜靜放行。
呢幾個位,就係「跑一次 sync OK」同「47 條 endpoint 用足一年都信得過」之間嘅距離。
一個心態
API docs 過時嘅根源唔係懶 —— 係 docs 同 code 本身就分開兩個 source。靠人手對齊,一定有漏。
呢個 workflow 嘅重點:將 single source 嘅範圍縮到淨返一層(route handler 入面嘅 Zod schema),其餘幾層全部係 derived artifacts。Derived 出嚟嘅嘢 Claude 識生,唔使人手維護。
- ✅ Schema-first:Zod / Pydantic 一定要喺 route handler 入面定義。手寫 JSON schema 永遠落後。
- ✅ 乜都 codegen:types / examples / markdown docs 全部由 spec 生出嚟。
- ✅ Pre-commit 攔截:docs 唔同步嘅 PR 唔可以入 main,CI 都要一齊把關。
- ⚠️ Staging endpoint 要穩定:example refresh 跑落真實 staging,唔可以連去 dev。Token 用唯讀。
下個 sprint 加新 endpoint 嘅時候,試吓 /api-doc 一句話搞掂佢。半年之後再望返轉頭,47 條 endpoint 嘅 docs 仲係同 code 對齊。客戶 integration team 都唔再寫投訴 email。
文中工具 · 連結
- Claude Code CLI· 付費
開發者用 — terminal 入面同 Claude pair coding
睇完想同 Claude 一齊行一次?
撳一撳,就將成段 tutor 指示(連埋成篇文嘅內容)抄入剪貼簿。 貼入 Claude.ai 或 Claude Desktop,佢會用廣東話帶你一步一步行, 每步問你填關鍵位,最後畀返一個專為你情況寫嘅 prompt 帶走。
- 創作者 · 25 分鐘
MCP servers 入門:5 個最有用 + 10 分鐘 install
Claude Code 想連 Notion / Slack / GitHub / database —— Claude 自己唔識用外部服務。MCP 解決:install server 之後 Claude 即時可以 query。介紹 5 個最有用 + install 步驟。
- 創作者 · 30 分鐘
CLAUDE.md 寫得啱:Claude Code 自動跟你 project 規矩,唔再次次解釋
Claude Code 自動讀 CLAUDE.md 做背景,但寫到似 README 等於白寫。教你 4 個必備 section、點驗收、點逐步改善,由今日開始 Claude 跟你 project 規矩跑。
- 創作者 · 45 分鐘
Claude Code 唔使開 terminal 都跑得:headless + cron 起夜貓自動化 workflow
Claude Code 唔淨係 interactive。Headless mode 可以入 cron、launchd、GitHub Actions、npm script,凌晨自動跑 code health、dep 審查、PR review。教 4 個真實設定 + 3 個部署變化。