跳转到主要内容

概览

vendor 客户端调用真实的第三方 API,因此它们不属于单元套件。你以两种方式验证它们:vendor 调试 CLI(隔离演练某个客户端的操作,无需服务器)和运行中服务器上的 HTTP 路由(所有权门控的 bind → verify → fetch 路径)。
元数据(VendorInfo)无需凭据;传输操作需要针对该 vendor 的真实凭据。

vendor 调试 CLI

cli/vendor.cpp 工具(当 MIROBODY_BUILD_TOOLS 为 ON 时构建于 cli/ 下 —— 默认开启)直接驱动某个 vendor 的契约操作。子命令:
vendor list                                          # all registered vendors
vendor <id> info                                     # full metadata for one vendor
vendor <id> auth-url  --redirect URL [--state S]     # build the consent URL
vendor <id> providers [--user U]                     # connectable data sources
vendor <id> fetch     --user U --domain sleep [--start ISO] [--end ISO]
vendor <id> webhook   --file payload.json            # body from --file/--data/stdin
vendor <id> revoke    --user U [--provider slug]
凭据来自服务器所用的同一批 MIROBODY_VENDOR_<ID>_* 环境变量。
1

元数据(无需凭据)

确认你的 VendorInfo 完整且 id 已注册:
./build/cli/vendor list
./build/cli/vendor fitbit info
2

授权 URL

MIROBODY_VENDOR_FITBIT_CLIENT_ID=... \
  ./build/cli/vendor fitbit auth-url --redirect https://localhost/cb --state abc
检查该 URL 格式正确,并携带你的 scopes / state
3

Fetch

用一个真实的 access token,在某个时间窗内获取一个域:
MIROBODY_VENDOR_FITBIT_API_KEY=... \
  ./build/cli/vendor fitbit fetch --user - --domain heart_rate --start 2026-06-01 --end 2026-06-07
验证返回的 JSON 与该 vendor 有文档的形态相符,且不支持的域会抛错并给出清晰的消息。
4

Webhook(带签名的 vendor)

喂入一个捕获到的 payload 并确认签名验证:
./build/cli/vendor fitbit webhook --file sample_notification.json
再传入一个被篡改的请求体,确认它被拒绝。
5

Revoke

MIROBODY_VENDOR_FITBIT_API_KEY=... MIROBODY_VENDOR_FITBIT_CLIENT_ID=... \
MIROBODY_VENDOR_FITBIT_CLIENT_SECRET=... ./build/cli/vendor fitbit revoke --user -
对于桩操作,CLI 会打印该 vendor 的”not implemented”原因 —— 这是预期的,其本身也值得断言(该消息应点明它为何是桩)。

针对运行中的服务器

演练所有权门控的 HTTP 路径(所有路由都需要 bearer JWT;服务器监听 HTTP_PORT,默认 8080):
# 1. bind the external account id (PENDING)
curl -X POST "http://localhost:8080/vendors/fitbit/bind" \
  -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
  -d '{"external_user_id": "FITBIT_USER_ID"}'

# 2. verify ownership (-> VERIFIED)
curl -X POST "http://localhost:8080/vendors/fitbit/bind/verify" -H "Authorization: Bearer $JWT"

# 3. fetch a verified link's data
curl "http://localhost:8080/vendors/fitbit/data?domain=heart_rate&start=2026-06-01&end=2026-06-07" \
  -H "Authorization: Bearer $JWT"
确认在验证之前获取会被拒绝,且第二名用户不能 bind 同一个 external_user_idUNIQUE(vendor_id, external_user_id) 这道防线)。 对于 EHR(SMART on FHIR),走一遍浏览器流程:/health/ehr/providers/health/ehr/authorize/health/ehr/callback/health/ehr/sync,然后从 /fhir/Observation 读回已持久化的 Observation

用于 OAuth 回调的本地 HTTPS

许多 vendor 会拒绝非 HTTPS 的 redirect URI,因此一个普通的 http://localhost:8080 回调无法用于真实的同意流程。本地开发的选项:
  • 一个在 443 端口终止 TLS 的本地反向代理(nginx / Caddy),使用来自 mkcert 的受信任证书,转发到 localhost:8080,并在 hosts 文件中加一条把你的生产回调域名映射到 127.0.0.1 的记录 —— 从而让同一个 redirect URI 在本地和生产都能工作。
  • 一个隧道服务,如 ngrok(在本地测试期间也便于接收入站 webhook 以及用于 MCP_PUBLIC_URL)。
关键在于,向 vendor 呈现它所期望的确切 HTTPS 回调 URL,而无需为每次改动都部署一遍。

需要覆盖的内容

有效凭据 → auth-url 能构建,fetch 为每个支持的域返回有文档的 JSON,带签名的 webhook 能验证,revoke 成功。
空的 api_key / client_id → 一个点明缺失环境变量的清晰 VendorError。必填的 base_url(自托管 / EHR)为空 → 拒绝执行,而非猜测一个主机。
不支持的 DataDomain 抛错;空的日期窗使用 vendor 默认;被篡改的 webhook 签名被拒绝;桩操作报告其原因。

下一步

Provider 集成

构建你正在测试的 vendor

测试指南

Catch2 单元套件

OAuth 实现

同意、webhook、撤销

使用 Provider

bind / verify / data 路由